home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.Lib / TextEditControl.c < prev    next >
Encoding:
Text File  |  1994-07-13  |  81.8 KB  |  3,221 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         texteditcontrol.c
  5. ** Written by:      Eric Soldan
  6. ** Based on:        TESample, by Bryan Stearns
  7. ** Suggestions by:  Forrest Tanaka, Dave Radcliffe
  8. **
  9. ** Copyright © 1990-1993 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21. /* This is a control implementation of TextEdit.  The advantages to this are:
  22. **
  23. ** 1) Makes using TextEdit in a non-dialog window easy.
  24. ** 2) The TextEdit record is automatically associated with the window, since
  25. **    it is in the window's control list.
  26. ** 3) The TextEdit control can have scrollbars associated with it, and these
  27. **    are also kept in the window's control list.
  28. ** 4) Updating of the TextEdit record is much simpler, since all that is
  29. **    necessary is to draw the control (or all the window's controls with
  30. **    a DrawControls call).
  31. ** 5) There are simple calls to handle TextEdit events.
  32. ** 6) Undo is already supported.
  33. ** 7) A document length can be specified.  This length will not be exceeded
  34. **    when editing the TextEdit record.
  35. ** 8) When you close the window, the TextEdit record is disposed of.
  36. **    (This automatic disposal can easily be defeated.)
  37. **
  38. **
  39. ** To create a TextEdit control, you only need a single call.  For example:
  40. **
  41. **    CTENew(rViewCtl,            Resource ID of view control for TextEdit control.
  42. **           true,                 Control initially visible.
  43. **           window,                Window to hold TERecord.
  44. **           &teHndl,                Return handle for TERecord.
  45. **           &ctlRct,                Rect for TextEdit view control.
  46. **           &destRct,            destRct for TERecord
  47. **           &viewRct,            viewRct for TERecord
  48. **           &borderRct,            Used to frame a border.
  49. **           32000,                Max size for TERecord text.
  50. **           cteVScrollLessGrow    TERecord read-write, with vertical scroll
  51. **                                that leaves space for grow box.
  52. **    );
  53. **
  54. ** If you create a TextEdit control that is read-only, you will not be able
  55. ** to edit it, of course.  There will also be no blinking caret for that
  56. ** TextEdit control.  You will be able to select text and copy to the
  57. ** clipboard, but that is all.
  58.  
  59. ** Simply create destRct, viewRct, and borderRct appropriately, and
  60. ** then call CTENew (which stands for Control TENew).  If teHndl is returned
  61. ** nil, then CTENew failed.  Otherwise, you now have a TextEdit control in
  62. ** the window.
  63. **
  64. ** NOTE: There is a TextEdit bug (no way!!) such that you may need to set the
  65. **       viewRct right edge 2 bigger than the right edge of destRct.  If you
  66. **       do not do this, then there will be some clipping on the right edge in
  67. **       some cases.  Of course, you may want this.  You may want horizontal
  68. **       scrolling, and therefore you would want the destRct substantially
  69. **       larger than the viewRct.  If you don't want horizontal scrolling,
  70. **       then you probably don't want any clipping horizontally, and therefore
  71. **       you will need to set destRct.right 2 less than viewRct.right.
  72. **
  73. **
  74. ** If the CTENew call succeeds, you then have a TextEdit control in your
  75. ** window.  It will be automatically disposed of when you close the window.
  76. ** If you don't waht this to happen, then you can detach it from the
  77. ** view control which owns it.  To do this, you would to the following:
  78. **
  79. **  viewCtl = CTEViewFromTE(theTextEditHndl);
  80. **  if (viewCtl) SetControlReference(viewCtl, nil);
  81. **
  82. ** The view control keeps a reference to the TextEdit record in the refCon.
  83. ** If the refCon is cleared, then the view control does nothing.  So, all that
  84. ** is needed to detach a TextEdit record from a view control is to set the
  85. ** view control's refCon nil.  Now if you close the window, you will still
  86. ** have the TextEdit record.
  87. **
  88. **
  89. ** To remove a TextEdit control completely from a window, you make one call:
  90. **
  91. **  CTEDispose(theTextEditHndl);
  92. **
  93. ** This disposes of the TextEdit record, the view control, and any scrollbar
  94. ** controls that were created when the TextEdit control was created with
  95. ** the call CTENew.
  96. **
  97. **
  98. ** Events for TextEdit record are handled nearly automatically.  You can
  99. ** make one of 3 calls:
  100. **
  101. **  CTEClick(window, eventPtr, &action);
  102. **  CTEEvent(window, eventPtr, &action);
  103. **  CTEKey(window, eventPtr);
  104. **
  105. ** In each case, if the event was handled, true is returned.  CTEEvent simply
  106. ** calls either CTEClick or CTEKey, whichever is appropriate.
  107. **
  108. **
  109. ** Another call you will want to use is CTEEditMenu.  This is used to set the
  110. ** state of cut/copy/paste/clear for TextEdit controls.  It checks the active
  111. ** control to see if text is selected, if the control is read-only, etc.
  112. ** Based on this information, it sets cut/copy/paste/clear either active
  113. ** or inactive.  If any menu items are set active, it returns true.
  114. **
  115. **
  116. ** One more high-level call is CTEUndo().  In response to an undo menu item
  117. ** being selected by the user, just call CTEUndo(), and the edits the user
  118. ** has made will be undone.  (This includes undoing an undo.)
  119. **
  120. **
  121. ** The last high-level call is CTEClipboard.  Call it when you want to do a
  122. ** cut/copy/paste/clear for the active TextEdit control.  The value to pass
  123. ** is as follows:
  124. **
  125. **  2: cut
  126. **  3: copy
  127. **  4: paste
  128. **  5: clear
  129. **
  130. ** These are the same values you would pass to a DA for these actions.
  131. */
  132.  
  133.  
  134.  
  135. /*****************************************************************************/
  136.  
  137.  
  138.  
  139. #ifndef __TEXTEDITCONTROL__
  140. #include "TextEditControl.h"
  141. #endif
  142.  
  143. #ifndef __BALLOONS__
  144. #include <Balloons.h>
  145. #endif
  146.  
  147. #ifndef __CONTROLS__
  148. #include <Controls.h>
  149. #endif
  150.  
  151. #ifndef __DTSLib__
  152. #include "DTS.Lib.h"
  153. #endif
  154.  
  155. #ifndef __ERRORS__
  156. #include <Errors.h>
  157. #endif
  158.  
  159. #ifndef __EVENTS__
  160. #include <Events.h>
  161. #endif
  162.  
  163. #ifndef __FONTS__
  164. #include <Fonts.h>
  165. #endif
  166.  
  167. #ifndef __GESTALTEQU__
  168. #include <GestaltEqu.h>
  169. #endif
  170.  
  171. #ifndef __MEMORY__
  172. #include <Memory.h>
  173. #endif
  174.  
  175. #ifndef __MENUS__
  176. #include <Menus.h>
  177. #endif
  178.  
  179. #ifndef __OSEVENTS__
  180. #include <OSEvents.h>
  181. #endif
  182.  
  183. #ifndef __OSUTILS__
  184. #include <OSUtils.h>
  185. #endif
  186.  
  187. #ifndef __RESOURCES__
  188. #include <Resources.h>
  189. #endif
  190.  
  191. #ifndef __SCRAP__
  192. #include <Scrap.h>
  193. #endif
  194.  
  195. #ifndef __SCRIPT__
  196. #include <Script.h>
  197. #endif
  198.  
  199. #ifndef __TEXTSERVICES__
  200. #include <TextServices.h>
  201. #endif
  202.  
  203. #ifndef __TSMTE__
  204. #include "TSMTE.h"
  205. #endif
  206.  
  207. #ifndef __UTILITIES__
  208. #include "Utilities.h"
  209. #endif
  210.  
  211.  
  212.  
  213. /*****************************************************************************/
  214.  
  215. #ifdef powerc
  216. #pragma options align=mac68k
  217. #endif
  218. typedef struct cdefRsrcJMP {
  219.     long    jsrInst;
  220.     long    moveInst;
  221.     short    jmpInst;
  222.     long    jmpAddress;
  223. } cdefRsrcJMP;
  224. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  225. #ifdef powerc
  226. #pragma options align=reset
  227. #endif
  228.  
  229.  
  230.  
  231. /*****************************************************************************/
  232.  
  233.  
  234.  
  235. extern Boolean        gInBackground;
  236.  
  237. short    gTECtl    = rTECtl;
  238.  
  239. short    CTEGetLineNum(TEHandle te, short offset);
  240. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent);
  241.  
  242. static void                CTEInitialize(void);
  243. static pascal long        CTECtl(short varCode, ControlHandle ctl, short msg, long parm);
  244. static Boolean            GoFast(TEHandle teHndl, EventRecord *event);
  245. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  246.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon);
  247.  
  248. static pascal Boolean    PPCClikLoop(TEPtr pTE);
  249. static pascal void        PPCNoCaret(const Rect *r, TEPtr pTE);
  250.  
  251. static cdefRsrcJMPHndl    gCDEF;
  252. static Boolean            gCanGoSlow;
  253. static Boolean            gUseTSMTE;
  254. static WindowPtr        gTEWindow;
  255.  
  256.  
  257.  
  258. /*****************************************************************************/
  259.  
  260.  
  261.  
  262. TEClickLoopUPP    gDefaultClikLoopUPP;
  263.     /* The clikLoop TextEdit wants to use.  Our custom clikLoop must call
  264.     ** this as well.  The default TextEdit clikLoop is stored here. */
  265.  
  266. static ControlDefUPP    gCTECtlUPP;                /* Universal ProcPtr for CTECtl() */
  267. static TEClickLoopUPP    gClikLoopUPP;            /* Universal ProcPtr for our ClikLoop */
  268. static CaretHookUPP        gNoCaretHookUPP;        /* Universal ProcPtr for our CaretHook */
  269.  
  270.  
  271.  
  272. /*****************************************************************************/
  273.  
  274.  
  275.  
  276. static TEHandle            gActiveTEHndl;
  277.     /* Currently active TextEdit record.  (nil if none active.) */
  278.  
  279. static TEHandle            gFoundTEHndl;
  280.     /* Global value used to return info from the TextEdit control proc. */
  281.  
  282. static ControlHandle    gFoundViewCtl;
  283.     /* Global value used to return info from the TextEdit control proc. */
  284.  
  285. static pascal void        VActionProc(ControlHandle scrollCtl, short part);
  286. static pascal void        HActionProc(ControlHandle control, short part);
  287. static void                AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert);
  288.  
  289. #define kTELastForWind    1
  290. #define kCrChar            13
  291.  
  292.  
  293.  
  294. static void                dummyCTEActivate(Boolean active, TEHandle teHndl);
  295. static Boolean            dummyCTEClick(WindowPtr window, EventRecord *event, short *action);
  296. static ControlHandle    dummyCTECtlHit(void);
  297. static TEHandle            dummyCTEFindActive(WindowPtr window);
  298. static short            dummyCTEKey(WindowPtr window, EventRecord *event);
  299. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive);
  300. static void                dummyCTESetSelect(short start, short end, TEHandle teHndl);
  301. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl);
  302. static TEHandle            dummyCTEWindActivate(WindowPtr window, Boolean displayIt);
  303.  
  304. CTEActivateProcPtr           gcteActivate           = dummyCTEActivate;
  305. CTEClickProcPtr              gcteClick              = dummyCTEClick;
  306. CTECtlHitProcPtr             gcteCtlHit             = dummyCTECtlHit;
  307. CTEFindActiveProcPtr         gcteFindActive         = dummyCTEFindActive;
  308. CTEKeyProcPtr                gcteKey                = dummyCTEKey;
  309. CTENextProcPtr               gcteNext               = dummyCTENext;
  310. CTESetSelectProcPtr          gcteSetSelect          = dummyCTESetSelect;
  311. CTEViewFromTEProcPtr         gcteViewFromTE         = dummyCTEViewFromTE;
  312. CTEWindActivateProcPtr       gcteWindActivate       = dummyCTEWindActivate;
  313.  
  314.  
  315.  
  316. /*****************************************************************************/
  317. /*****************************************************************************/
  318. /*****************************************************************************/
  319.  
  320.  
  321.  
  322. /* Instead of calling the functions directly, you can reference the global
  323. ** proc pointers that reference the functions.  This keeps everything from
  324. ** being linked in.  The default global proc pointers point to dummy functions
  325. ** that behave as if there aren't any TextEdit controls.  The calls can still be
  326. ** made, yet the runtime behavior is such that it will operate as if there
  327. ** no instances of the TextEdit control.  This allows intermediate code to access
  328. ** the functions or not without automatically linking in all sorts of stuff
  329. ** into the application that isn't desired.  To change the global proc pointers
  330. ** so that they point to the actual functions, just call CTEInitialize() once
  331. ** in the beginning of the application.  If CTEInitialize() is referenced, it will
  332. ** get linked in.  In turn, everything that it references directly or indirectly
  333. ** will get linked in. */
  334.  
  335. #pragma segment TextEditControl
  336. static void    CTEInitialize(void)
  337. {
  338.     if (gcteActivate != CTEActivate) {
  339.         gcteActivate           = CTEActivate;
  340.         gcteClick              = CTEClick;
  341.         gcteCtlHit             = CTECtlHit;
  342.         gcteFindActive         = CTEFindActive;
  343.         gcteKey                = CTEKey;
  344.         gcteNext               = CTENext;
  345.         gcteSetSelect          = CTESetSelect;
  346.         gcteViewFromTE         = CTEViewFromTE;
  347.         gcteWindActivate       = CTEWindActivate;
  348.  
  349.         CTEConvertClipboard(true, true);
  350.     }
  351. }
  352.  
  353.  
  354.  
  355. /*****************************************************************************/
  356.  
  357.  
  358.  
  359. /* Activate this TextEdit record.  If another is currently active, deactivate
  360. ** that one.  The view control for this TextEdit record is also flagged to
  361. ** indicate which was the last active one for this window.  If the previous
  362. ** active TextEdit record was in the same window, then flag the old one off
  363. ** for this window.  The whole point for this per-window flagging is so that
  364. ** activate events can reactivate the correct TextEdit control per window. */
  365.  
  366. #pragma segment TextEditControl
  367. void    CTEActivate(Boolean active, TEHandle teHndl)
  368. {
  369.     WindowPtr        tePort, oldPort;
  370.     ControlHandle    viewCtl;
  371.     TEHandle        te;
  372.     CTEDataHndl        teData;
  373.     short            oldDisplay, newDisplay;
  374.  
  375.     if (!teHndl) return;
  376.  
  377.     teData = nil;
  378.     viewCtl = CTEViewFromTE(teHndl);
  379.     if (viewCtl)
  380.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  381.  
  382.     if (!active) {
  383.         GetPort(&oldPort);
  384.         SetPort(tePort = (*teHndl)->inPort);
  385.         if(gUseTSMTE)
  386.             DeactivateTSMDocument((*teData)->docID);
  387.         TEDeactivate(teHndl);
  388.         if (teHndl == gActiveTEHndl)
  389.             gActiveTEHndl = nil;
  390.         if (viewCtl)
  391.             CTEUpdate(teHndl, viewCtl, true);
  392.         SetPort(oldPort);
  393.         return;
  394.     }
  395.  
  396.     if (!viewCtl)               return;
  397.     if (!(*viewCtl)->contrlVis) return;
  398.  
  399.     (*teData)->mode |= cteActive;
  400.     GetPort(&oldPort);
  401.     SetPort(tePort = (*teHndl)->inPort);
  402.  
  403.     if (!gInBackground) {
  404.         if(gUseTSMTE)
  405.             ActivateTSMDocument((*teData)->docID);
  406.         TEActivate(gActiveTEHndl = teHndl);
  407.     }
  408.  
  409.     CTEUpdate(teHndl, viewCtl, true);
  410.     SetPort(oldPort);
  411.         /* Let TextEdit know that it is supposed to be active. */
  412.  
  413.     for (viewCtl = nil;;) {
  414.         viewCtl = CTENext(tePort, &te, viewCtl, 1, false);
  415.         if (!viewCtl) break;
  416.         if (te != teHndl) {
  417.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  418.             oldDisplay = (*teData)->mode;
  419.             newDisplay = (oldDisplay & (0xFFFF - cteActive));
  420.             if (oldDisplay != newDisplay) {
  421.                 (*teData)->mode = newDisplay;
  422.                 CTEActivate(false, te);
  423.             }
  424.         }
  425.     }
  426. }
  427.  
  428.  
  429.  
  430. static void    dummyCTEActivate(Boolean active, TEHandle teHndl)
  431. {
  432. #ifndef __MWERKS__
  433. #pragma unused (active, teHndl)
  434. #endif
  435. }
  436.  
  437.  
  438.  
  439. /*****************************************************************************/
  440.  
  441.  
  442.  
  443. /* This is called when a mouseDown occurs in the content of a window.  It
  444. ** returns true if the mouseDown caused a TextEdit action to occur.  Events
  445. ** that are handled include if the user clicks on a scrollbar that is
  446. ** associated with a TextEdit control. */
  447.  
  448. #pragma segment TextEditControl
  449. Boolean    CTEClick(WindowPtr window, EventRecord *event, short *action)
  450. {
  451.     WindowPtr        oldPort;
  452.     Point            mouseLoc;
  453.     TEHandle        te, teActive;
  454.     ControlHandle    ctlHit, viewCtl;
  455.     CTEDataHndl        teData;
  456.     Boolean            vert;
  457.     short            extendSelect, part, value, newValue, lh, mode;
  458.  
  459.     static ControlActionUPP    hcupp, vcupp;
  460.  
  461.     if (action)
  462.         *action = 0;
  463.  
  464.     GetPort(&oldPort);
  465.     if (!((WindowPeek)window)->hilited) return(false);
  466.  
  467.     SetPort(window);
  468.     mouseLoc = event->where;
  469.     GlobalToLocal(&mouseLoc);
  470.  
  471.     if (!(viewCtl = CTEFindCtl(window, event, &te, &ctlHit))) return(false);
  472.  
  473.     if (viewCtl == ctlHit) {
  474.             /* See if the user clicked directly on the view control for a
  475.             ** TextEdit record.  If so, we definitely have some work to do. */
  476.         if ((*viewCtl)->contrlHilite != 255) {
  477.             if (te != gActiveTEHndl) {
  478.                 CTEActivate(true, te);
  479.                 if (action)
  480.                     *action = -1;
  481.                 SetPort(oldPort);
  482.                 return(true);
  483.                     /* If user clicked on TextEdit control other than the
  484.                     ** currently active control, then activate it.  This is our
  485.                     ** only action in this case. */
  486.             }
  487.             extendSelect = ((event->modifiers & shiftKey) != 0);
  488.                 /* Extend-select may be occuring. */
  489.  
  490.             gCanGoSlow = true;
  491.                 /* There is a slow-zone around the TextEdit area for slow extend-select.
  492.                 ** Allow this zone to slow down selection. */
  493.  
  494.                 if (gUseTSMTE) {
  495.                     if (!TSMEvent(event))
  496.                         TEClick(mouseLoc, extendSelect, te);
  497.                 }
  498.                 else TEClick(mouseLoc, extendSelect, te);
  499.                     /* Do the extend-select thing.  Most of the work is handled by
  500.                     ** TextEdit.  The only thing we have to do is to update the
  501.                     ** scrollbars while the user is extending the select.  This is
  502.                     ** taken care of by our custom clikLoop procedure. */
  503.  
  504.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  505.             (*teData)->newUndo = true;
  506.  
  507.             SetPort(oldPort);
  508.             return(true);
  509.         }
  510.     }
  511.  
  512. /* We didn't hit the view control for a TextEdit record, but don't give up yet.
  513. ** The user may be clicking on a related scrollbar.  Let's find out... */
  514.  
  515.     if (WhichControl(mouseLoc, event->when, window, &ctlHit)) {
  516.             /* The user did click on a control.  But is it a scrollbar
  517.             ** for a TextEdit control?  Stay tuned... */
  518.  
  519.         te = CTEFromScroll(ctlHit, &viewCtl);
  520.  
  521.         if (te) {        /* It was a related scrollbar. */
  522.  
  523.             if ((*viewCtl)->contrlHilite != 255) {
  524.                 if (te != gActiveTEHndl) {
  525.                     CTEActivate(true, te);
  526.                     if (action)
  527.                         *action = -1;
  528.                     SetPort(oldPort);
  529.                     return(true);
  530.                         /* If user clicked on TextEdit control other than the
  531.                         ** currently active control, then activate it.  This is our
  532.                         ** only action in this case. */
  533.                 }
  534.             }
  535.  
  536.             vert = ((*ctlHit)->contrlRect.top <= (*viewCtl)->contrlRect.top);
  537.                 /* Horizontal or vertical scroll.  Only the rect knows. */
  538.  
  539.             part = FindControl(mouseLoc, window, &ctlHit);
  540.  
  541.             switch (part) {
  542.                 case 0:        /* Inactive scrollbar. */
  543.                     break;
  544.                 case inThumb:
  545.                     value = GetControlValue(ctlHit);
  546.                     part  = TrackControl(ctlHit, mouseLoc, nil);
  547.                     if (part) {
  548.                         newValue = GetControlValue(ctlHit);
  549.                         if (value != newValue) {    /* If scrollbar value changed... */
  550.                             if (vert) {
  551.                                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  552.                                 mode   = (*teData)->mode;
  553.                                 if (mode & cteScrollFullLines) {
  554.                                     if (!(mode & cteStyledTE)) {
  555.                                         lh = CTEGetLineHeight(te, 1, nil);
  556.                                         if (lh) {
  557.                                             newValue += (lh >> 1);
  558.                                             newValue /= lh;
  559.                                             newValue *= lh;
  560.                                             SetControlValue(ctlHit, newValue);
  561.                                         }
  562.                                     }
  563.                                 }
  564.                                 TEScroll(0, value - newValue, te);
  565.                             }
  566.                             else
  567.                                 TEScroll(value - newValue, 0, te);
  568.                         }
  569.                     }
  570.                     break;
  571.  
  572.                 default:
  573.                     teActive = gActiveTEHndl;
  574.                     gActiveTEHndl = te;
  575.                         /* This is a hack way to pass the action procedure
  576.                         ** which TextEdit record we are dealing with. */
  577.  
  578.                     if (vert) {
  579.                         if (!vcupp) vcupp = NewControlActionProc(VActionProc);
  580.                         TrackControl(ctlHit, mouseLoc, vcupp);
  581.                     }
  582.                     else {
  583.                         if (!hcupp) hcupp = NewControlActionProc(HActionProc);
  584.                         TrackControl(ctlHit, mouseLoc, hcupp);
  585.                     }
  586.  
  587.                     gActiveTEHndl = teActive;
  588.                         /* Unhack our previous hack. */
  589.                     break;
  590.             }
  591.  
  592.             SetPort(oldPort);
  593.             return(true);
  594.         }
  595.     }
  596.  
  597.     SetPort(oldPort);
  598.     return(false);
  599. }
  600.  
  601.  
  602.  
  603. static Boolean    dummyCTEClick(WindowPtr window, EventRecord *event, short *action)
  604. {
  605. #ifndef __MWERKS__
  606. #pragma unused (window, event)
  607. #endif
  608.  
  609.     if (action)
  610.         *action = 0;
  611.     return(false);
  612. }
  613.  
  614.  
  615.  
  616. /*****************************************************************************/
  617.  
  618.  
  619.  
  620. /* This is the custom clikLoop, which is called from the assembly glue code.
  621. ** This handles updating the scrollbars as the user is drag-selecting in
  622. ** the TextEdit control. */
  623.  
  624. #pragma segment TextEditControl
  625. void    CTEClikLoop(void)
  626. {
  627.     WindowPtr        oldPort, window;
  628.     TEHandle        te;
  629.     Point            mouseLoc;
  630.     Rect            viewRct;
  631.     RgnHandle        rgn;
  632.     short            dl, dr, dt, db;
  633.     long            tick;
  634.  
  635.     GetPort(&oldPort);
  636.     SetPort(window = (WindowPtr)(*gActiveTEHndl)->inPort);
  637.  
  638.     te = gActiveTEHndl;
  639.         /* This better be what the user is dragging, or we did something
  640.         ** wrong elsewhere.
  641.         */
  642.  
  643.     GetMouse(&mouseLoc);
  644.     viewRct = (*te)->viewRect;
  645.  
  646.     if (!PtInRect(mouseLoc, &viewRct)) {
  647.         /* User is outside the TextEdit area, so scrolling is happening. */
  648.  
  649.         tick = gCanGoSlow;
  650.         if (tick)
  651.             tick = TickCount();
  652.                 /* As an extra feature, there is a zone around the TextEdit
  653.                 ** viewRct that the scroll will be slowed down.  If the user
  654.                 ** drags outside the viewRct outside this zone, then scrolling
  655.                 ** occurs as fast as possible. */
  656.  
  657.         rgn = NewRgn();
  658.         GetClip(rgn);
  659.         ClipRect(&(window->portRect));
  660.             /* The clipRgn is set to protect everything outside viewRct.
  661.             ** This doesn't work very well when we want to change
  662.             ** the scrollbars.  Save the old and open it up.
  663.             */
  664.  
  665.         dl = viewRct.left - mouseLoc.h;
  666.         dr = mouseLoc.h   - viewRct.right;
  667.         dt = viewRct.top  - mouseLoc.v;
  668.         db = mouseLoc.v   - viewRct.bottom;
  669.             /* Check the delta value for each side of viewRct.  This will
  670.             ** be used to determine if we should scroll fast or slow.
  671.             */
  672.  
  673.         CTEAdjustScrollValues(te);
  674.             /* Scroll them puppies. */
  675.  
  676.         SetClip(rgn);                                /* restore clip */
  677.         DisposeRgn(rgn);
  678.             /* Make Mr. clipRgn happy again. */
  679.  
  680.         if ((dl < 16) && (dr < 16) && (dt < 16) && (db < 16))
  681.             while (tick + 10 > TickCount()) {};
  682.                 /* Do it really slow.  (This is important on very fast machines.) */
  683.     }
  684.  
  685.     SetPort(oldPort);
  686. }
  687.  
  688.  
  689.  
  690. /*****************************************************************************/
  691.  
  692.  
  693.  
  694. /* Do the cut/copy/paste/clear operations for the currently active
  695. ** TextEdit control.  Caller assumes appropriateness of the call.  Typically,
  696. ** this routine won't be called at an inappropriate time, since the menu
  697. ** item should be enabled or disabled correctly.
  698. ** Use CTEEditMenu to set the menu items undo/cut/copy/paste/clear correctly
  699. ** for the active TextEdit control.  Since undo isn't currently supported,
  700. ** all that CTEEditMenu does for the undo case is to deactivate it right now. */
  701.  
  702. #pragma segment TextEditControl
  703. ControlHandle    CTEClipboard(short menuID)
  704. {
  705.     WindowPtr        oldPort;
  706.     TEHandle        te;
  707.     ControlHandle    viewCtl;
  708.     CTEDataHndl        teData;
  709.     long            maxTextLen, charsToAdd;
  710.  
  711.     if (!(te = gActiveTEHndl))          return(nil);
  712.     if (!(viewCtl = CTEViewFromTE(te))) return(nil);
  713.  
  714.     GetPort(&oldPort);
  715.     SetPort((*te)->inPort);
  716.     switch (menuID) {
  717.         case 2:
  718.             CTENewUndo(viewCtl, true);
  719.             TECut(te);
  720.             break;
  721.         case 3:
  722.             TECopy(te);
  723.             viewCtl = nil;
  724.             break;
  725.         case 4:
  726.             if (viewCtl) {
  727.                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  728.                 maxTextLen  = (*teData)->maxTextLen;
  729.                 charsToAdd  = TEGetScrapLength();
  730.                 charsToAdd -= ((*te)->selEnd - (*te)->selStart);
  731.                 if ((*te)->teLength + charsToAdd <= maxTextLen) {
  732.                     CTENewUndo(viewCtl, true);
  733.                     if ((*teData)->mode & cteStyledTE)
  734.                         TEStylePaste(te);
  735.                     else
  736.                         TEPaste(te);
  737.                 }
  738.                 else viewCtl = nil;
  739.             }
  740.             break;
  741.         case 5:
  742.             CTENewUndo(viewCtl, true);
  743.             TEDelete(te);
  744.             break;
  745.     }
  746.  
  747.     CTEAdjustTEBottom(te);
  748.     CTEAdjustScrollValues(te);
  749.     SetPort(oldPort);
  750.  
  751.     return(viewCtl);
  752. }
  753.  
  754.  
  755.  
  756. /*****************************************************************************/
  757.  
  758.  
  759.  
  760. #pragma segment TextEditControl
  761. void    CTEConvertClipboard(Boolean convertClipboard, Boolean becomingActive)
  762. {
  763. #ifndef __MWERKS__
  764. #pragma unused (convertClipboard, becomingActive)
  765. #endif
  766. }
  767.  
  768.  
  769.  
  770. /*****************************************************************************/
  771.  
  772.  
  773.  
  774. #pragma segment TextEditControl
  775. static pascal long    CTECtl(short varCode, ControlHandle ctl, short msg, long parm)
  776. {
  777. #ifndef __MWERKS__
  778. #pragma unused (varCode)
  779. #endif
  780.  
  781.     Rect            viewRct;
  782.     TEHandle        te;
  783.     CTEDataHndl        teData;
  784.     ControlHandle    scrollCtl;
  785.     short            i;
  786.  
  787.     te = (TEHandle)GetControlReference(ctl);
  788.     if (te)
  789.         viewRct = (*ctl)->contrlRect;
  790.     else
  791.         SetRect(&viewRct, 0, 0, 0, 0);
  792.  
  793.     switch (msg) {
  794.         case drawCntl:
  795.             CTEUpdate(te, ctl, false);
  796.             break;
  797.  
  798.         case testCntl:
  799.             if (PtInRect(*(Point *)&parm, &viewRct)) {
  800.                 gFoundViewCtl = ctl;
  801.                 gFoundTEHndl  = te;
  802.                 return(1);
  803.             }
  804.             return(0);
  805.             break;
  806.  
  807.         case calcCRgns:
  808.         case calcCntlRgn:
  809.             if (msg == calcCRgns)
  810.                 parm &= 0x00FFFFFF;
  811.             RectRgn((RgnHandle)parm, &viewRct);
  812.             break;
  813.  
  814.         case initCntl:
  815.             break;
  816.  
  817.         case dispCntl:
  818.             if (te) {
  819.                 if (te == gActiveTEHndl)
  820.                     gActiveTEHndl = nil;
  821.                 TEDispose(te);
  822.                 teData = (CTEDataHndl)(*ctl)->contrlData;
  823.                 if (teData) {
  824.                     if ((*teData)->undoText)
  825.                         DisposeHandle((Handle)(*teData)->undoText);
  826.                     if ((*teData)->undoStyl)
  827.                         DisposeHandle((Handle)(*teData)->undoStyl);
  828.                     if ((*teData)->docID)
  829.                         DeleteTSMDocument((*teData)->docID);
  830.                     DisposeHandle((Handle)teData);
  831.                 }
  832.                 for (i = 0; i < 2; ++i) {
  833.                     scrollCtl = CTEScrollFromView(ctl, i);
  834.                     if (scrollCtl)
  835.                         DisposeControl(scrollCtl);
  836.                 }
  837.             }
  838.             break;
  839.  
  840.         case posCntl:
  841.             break;
  842.  
  843.         case thumbCntl:
  844.             break;
  845.  
  846.         case dragCntl:
  847.             break;
  848.  
  849.         case autoTrack:
  850.             break;
  851.     }
  852.  
  853.     return(0);
  854. }
  855.  
  856.  
  857.  
  858. /*****************************************************************************/
  859.  
  860.  
  861.  
  862. /* The TextEdit control that was hit by calling FindControl is saved in a
  863. ** global variable, since the CDEF has no way of returning what kind it was.
  864. ** To determine that it was a TextEdit control that was hit, first call this
  865. ** function.  The first call returns the old value in the global variable,
  866. ** plus it resets the global to nil.  Then call FindControl(), and then
  867. ** call this function again.  If it returns nil, then a TextEdit control
  868. ** wasn't hit.  If it returns non-nil, then it was a TextEdit control that
  869. ** was hit, and specifically the one returned. */
  870.  
  871. #pragma segment TextEditControl
  872. ControlHandle    CTECtlHit(void)
  873. {
  874.     ControlHandle    ctl;
  875.  
  876.     ctl = gFoundViewCtl;
  877.     gFoundViewCtl = nil;
  878.     return(ctl);
  879. }
  880.  
  881.  
  882.  
  883. static ControlHandle    dummyCTECtlHit(void)
  884. {
  885.     return(nil);
  886. }
  887.  
  888.  
  889.  
  890. /*****************************************************************************/
  891.  
  892.  
  893.  
  894. /* Disposes of the TERecord, TextEdit control, and any related scrollbars. */
  895.  
  896. #pragma segment TextEditControl
  897. void    CTEDispose(TEHandle teHndl)
  898. {
  899.     WindowPtr    oldPort;
  900.  
  901.     if (teHndl) {
  902.         GetPort(&oldPort);
  903.         SetPort((*teHndl)->inPort);
  904.         TEDispose(CTEDisposeView(CTEViewFromTE(teHndl)));
  905.             /* Dispose of the TextEdit control completely.  This includes
  906.             ** scrollbars, as well as the TextEdit view control.
  907.             */
  908.         SetPort(oldPort);
  909.     }
  910. }
  911.  
  912.  
  913.  
  914. /*****************************************************************************/
  915.  
  916.  
  917.  
  918. /* Dispose of the view control and related scrollbars.  This function also
  919. ** returns the handle to the TextEdit record, since it was just orphaned.
  920. ** Use this function if you want to get rid of a TextEdit control, but you
  921. ** want to keep the TextEdit record. */
  922.  
  923. #pragma segment TextEditControl
  924. TEHandle    CTEDisposeView(ControlHandle viewCtl)
  925. {
  926.     TEHandle        te;
  927.     short            vert;
  928.     ControlHandle    ctl;
  929.  
  930.     if (!viewCtl) return(nil);
  931.  
  932.     te = (TEHandle)GetControlReference(viewCtl);
  933.     SetControlReference(viewCtl, (long)nil);
  934.  
  935.     for (vert = 0; vert < 2; ++vert) {
  936.         ctl = CTEScrollFromView(viewCtl, vert);
  937.         if (ctl)
  938.             DisposeControl(ctl);
  939.     }
  940.  
  941.     DisposeControl(viewCtl);
  942.     return(te);
  943. }
  944.  
  945.  
  946.  
  947. /*****************************************************************************/
  948.  
  949.  
  950.  
  951. /* Returns the full document height. */
  952.  
  953. #pragma segment TextEditControl
  954. short    CTEDocHeight(TEHandle teHndl)
  955. {
  956.     short        h, lh, a;
  957.     TextStyle    st;
  958.  
  959.     if (!teHndl) return(0);
  960.  
  961.     h = TEGetHeight((*teHndl)->nLines, 1, teHndl);
  962.         /* Get the whole doc height. */
  963.  
  964.     if ((*teHndl)->nLines != CTENumTextLines(teHndl)) {        /* If # of lines is wrong by one... */
  965.         TEGetStyle((*teHndl)->teLength, &st, &lh, &a, teHndl);
  966.         h += lh;                                            /* Add in height of last line. */
  967.     }
  968.  
  969.     return(h);
  970. }
  971.  
  972.  
  973.  
  974. /*****************************************************************************/
  975.  
  976.  
  977.  
  978. /* Enable or disable edit menu items based on the active TextEdit control.
  979. ** You pass the menu ID of the undo item in undoID, and the menu ID of the
  980. ** cut item in cutID.  If undoID or cutID is non-zero, then some action is
  981. ** performed.  If you pass a non-zero value for cutID, then the other menu
  982. ** items cut/copy/paste/clear are updated to reflect the status of the
  983. ** active TextEdit control. */
  984.  
  985. #pragma segment TextEditControl
  986. Boolean    CTEEditMenu(Boolean *activeItem, short editMenu, short undoID, short cutID)
  987. {
  988.     TEHandle        te;
  989.     MenuHandle        menu;
  990.     Boolean            active;
  991.     ControlHandle    viewCtl;
  992.     CTEDataHndl        teData;
  993.     long            dataLen, scrapOffset;
  994.  
  995.     active = false;
  996.     if (activeItem) *activeItem = false;
  997.     menu = GetMenuHandle(editMenu);
  998.  
  999.     if (undoID)
  1000.         DisableItem(menu, undoID);
  1001.  
  1002.     if (cutID) {
  1003.         DisableItem(menu, cutID);            /* Disable cut. */
  1004.         DisableItem(menu, cutID + 1);        /* Disable copy. */
  1005.         DisableItem(menu, cutID + 2);        /* Disable paste. */
  1006.         DisableItem(menu, cutID + 3);        /* Disable clear. */
  1007.     }
  1008.  
  1009.     if (!(te = gActiveTEHndl)) return(false);
  1010.  
  1011.     if (undoID) {
  1012.         viewCtl = CTEViewFromTE(te);
  1013.         if (viewCtl) {
  1014.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1015.             if ((*teData)->undoText) {
  1016.                 EnableItem(menu, undoID);
  1017.                 active = true;
  1018.             }
  1019.         }
  1020.     }
  1021.  
  1022.     if (cutID) {
  1023.         if ((*te)->selStart != (*te)->selEnd) {
  1024.             if (!CTEReadOnly(te)) {
  1025.                 EnableItem(menu, cutID);        /* Enable cut. */
  1026.                 EnableItem(menu, cutID + 3);    /* Enable clear. */
  1027.             }
  1028.             active = true;
  1029.             EnableItem(menu, cutID + 1);        /* Enable copy. */
  1030.         }
  1031.         if (!CTEReadOnly(te)) {
  1032.             dataLen = GetScrap(nil, 'TEXT', &scrapOffset);
  1033.             if (dataLen > 0) {
  1034.                 active = true;
  1035.                 EnableItem(menu, cutID + 2);        /* Enable paste. */
  1036.             }
  1037.         }
  1038.     }
  1039.  
  1040.     if (activeItem)
  1041.         *activeItem = active;
  1042.  
  1043.     return(true);
  1044. }
  1045.  
  1046.  
  1047.  
  1048. /*****************************************************************************/
  1049.  
  1050.  
  1051.  
  1052. /* Handle the event if it applies to the active TextEdit control.  If some
  1053. ** action occured due to the event, return true. */
  1054.  
  1055. #pragma segment TextEditControl
  1056. Boolean    CTEEvent(WindowPtr window, EventRecord *event, short *action)
  1057. {
  1058.     WindowPtr    clickWindow;
  1059.     short        actn;
  1060.  
  1061.     if (action)
  1062.         *action = 0;
  1063.  
  1064.     switch(event->what) {
  1065.  
  1066.         case mouseDown:
  1067.             if (FindWindow(event->where, &clickWindow) == inContent)
  1068.                 if (window == clickWindow)
  1069.                     if (((WindowPeek)window)->hilited) return(CTEClick(window, event, action));
  1070.             break;
  1071.  
  1072.         case autoKey:
  1073.         case keyDown:
  1074.             if (!(event->modifiers & cmdKey)) {
  1075.                 actn = CTEKey(window, event);
  1076.                 if (action)
  1077.                     *action = actn;
  1078.                 if (actn) return(true);
  1079.             }
  1080.             break;
  1081.     }
  1082.  
  1083.     return(false);
  1084. }
  1085.  
  1086.  
  1087.  
  1088. /*****************************************************************************/
  1089.  
  1090.  
  1091.  
  1092. /* Returns the active TextEdit control, if any.  If nil is passed in, then
  1093. ** the return value represents whatever TextEdit control is active, independent
  1094. ** of what window it is in.  If a window is passed in, then it returns a
  1095. ** TextEdit control only if the active control is in the specified window.
  1096. ** If the active TextEdit control is in some other window, then nil is returned. */
  1097.  
  1098. #pragma segment TextEditControl
  1099. TEHandle    CTEFindActive(WindowPtr window)
  1100. {
  1101.     if (!window) return(gActiveTEHndl);
  1102.         /* User wants whatever is active one, for whatever window. */
  1103.  
  1104.     if (!gActiveTEHndl) return(nil);
  1105.     if (window != (*gActiveTEHndl)->inPort) return(nil);
  1106.     return(gActiveTEHndl);
  1107. }
  1108.  
  1109.  
  1110.  
  1111. static TEHandle    dummyCTEFindActive(WindowPtr window)
  1112. {
  1113. #ifndef __MWERKS__
  1114. #pragma unused (window)
  1115. #endif
  1116.     return(nil);
  1117. }
  1118.  
  1119.  
  1120.  
  1121. /*****************************************************************************/
  1122.  
  1123.  
  1124.  
  1125. /* This determines if a TextEdit control was clicked on directly.  This does
  1126. ** not determine if a related scrollbar was clicked on.  If a TextEdit
  1127. ** control was clicked on, then true is returned, as well as the TextEdit
  1128. ** handle and the handle to the view control. */
  1129.  
  1130. #pragma segment TextEditControl
  1131. ControlHandle    CTEFindCtl(WindowPtr window, EventRecord *event, TEHandle *teHndl, ControlHandle *ctlHit)
  1132. {
  1133.     WindowPtr        oldPort;
  1134.     Point            mouseLoc;
  1135.     ControlHandle    ctl, tectl;
  1136.     TEHandle        te;
  1137.  
  1138.     if (ctlHit) *ctlHit = nil;
  1139.     if (teHndl) *teHndl = nil;
  1140.  
  1141.     gFoundTEHndl = nil;
  1142.  
  1143.     if (window) {
  1144.         GetPort(&oldPort);
  1145.         SetPort(window);
  1146.         mouseLoc = event->where;
  1147.         GlobalToLocal(&mouseLoc);
  1148.         SetPort(oldPort);
  1149.  
  1150.         if (!WhichControl(mouseLoc, 0, window, &ctl)) return(nil);
  1151.             /* Didn't hit a thing, so forget it. */
  1152.  
  1153.         te = CTEFromScroll(ctl, &tectl);
  1154.         if (te) {
  1155.             if (ctlHit)
  1156.                 *ctlHit = ctl;
  1157.             if (teHndl)
  1158.                 *teHndl = te;
  1159.             return(tectl);
  1160.         }
  1161.  
  1162.         FindControl(mouseLoc, window, &ctl);
  1163.         if (!ctl)                                                        return(nil);
  1164.         if (StripAddress((*ctl)->contrlDefProc) != StripAddress(gCDEF)) return(nil);
  1165.             /* Control hit was above TE control, so we didn't hit a TE control. */
  1166.         if (ctlHit)
  1167.             *ctlHit = ctl;
  1168.         if (teHndl)
  1169.             *teHndl = gFoundTEHndl;
  1170.         if (gFoundTEHndl) return(ctl);
  1171.     }
  1172.  
  1173.     return(nil);
  1174. }
  1175.  
  1176.  
  1177.  
  1178. /*****************************************************************************/
  1179.  
  1180.  
  1181.  
  1182. /* Find the TextEdit record that is related to the indicated scrollbar. */
  1183.  
  1184. #pragma segment TextEditControl
  1185. TEHandle    CTEFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
  1186. {
  1187.     WindowPtr        window;
  1188.     ControlHandle    viewCtl;
  1189.     TEHandle        te;
  1190.  
  1191.     if (!IsScrollBar(scrollCtl)) {
  1192.         if (retCtl) *retCtl = nil;
  1193.         return(nil);
  1194.     }
  1195.  
  1196.     window = (*scrollCtl)->contrlOwner;
  1197.  
  1198.     for (viewCtl = nil;;) {
  1199.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  1200.         if (!viewCtl) return(nil);
  1201.         if (viewCtl == (ControlHandle)GetControlReference(scrollCtl)) {
  1202.             if (retCtl) *retCtl = viewCtl;
  1203.             return(te);
  1204.         }
  1205.     }
  1206. }
  1207.  
  1208.  
  1209.  
  1210. /*****************************************************************************/
  1211.  
  1212.  
  1213.  
  1214. /* Hide the designated TextEdit control and related scrollbars. */
  1215.  
  1216. #pragma segment TextEditControl
  1217. Rect    CTEHide(TEHandle teHndl)
  1218. {
  1219.     ControlHandle    viewCtl, scrollCtl;
  1220.     short            i, mode;
  1221.     CTEDataHndl        teData;
  1222.     Rect            viewRct, brdrRct;
  1223.  
  1224.     SetRect(&brdrRct, 0, 0, 0, 0);
  1225.  
  1226.     if (teHndl) {
  1227.         CTEActivate(false, teHndl);
  1228.         viewCtl = CTEViewFromTE(teHndl);
  1229.         if (viewCtl) {
  1230.             HideControl(viewCtl);
  1231.             for (i = 0; i < 2; i++) {
  1232.                 scrollCtl = CTEScrollFromView(viewCtl, i);
  1233.                 if (scrollCtl)
  1234.                     HideControl(scrollCtl);
  1235.             }
  1236.  
  1237.             teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1238.             mode    = (*teData)->mode;
  1239.             viewRct = (*teHndl)->viewRect;
  1240.             brdrRct = (*teData)->brdrRect;
  1241.         
  1242.             if (EmptyRect(&brdrRct)) brdrRct = viewRct;
  1243.  
  1244.             if (mode & cteVScroll) brdrRct.right  += 15;
  1245.             if (mode & cteHScroll) brdrRct.bottom += 15;
  1246.  
  1247.             if (mode & cteShowActive) InsetRect(&brdrRct, -3, -3);
  1248.         }
  1249.     }
  1250.  
  1251.     return(brdrRct);
  1252. }
  1253.  
  1254.  
  1255.  
  1256. /*****************************************************************************/
  1257.  
  1258.  
  1259.  
  1260. /* Blink the caret in the active TextEdit control.  The active TextEdit
  1261. ** control may be read-only, in which case the caret does not blink. */
  1262.  
  1263. #pragma segment TextEditControl
  1264. void    CTEIdle(void)
  1265. {
  1266.     WindowPtr        window;
  1267.     ControlHandle    viewCtl;
  1268.     Rect            rct;
  1269.  
  1270.     if (gActiveTEHndl) {
  1271.         if (!(viewCtl = CTEViewFromTE(gActiveTEHndl))) return;
  1272.         if (!((*viewCtl)->contrlVis))                  return;
  1273.         if ((*viewCtl)->contrlHilite == 255)           return;
  1274.         window = (*gActiveTEHndl)->inPort;
  1275.         if (((WindowPeek)window)->hilited) {
  1276.             if (GetWRefCon(window)) {
  1277.                 rct = (*(((WindowPeek)window)->updateRgn))->rgnBBox;
  1278.                 if (EmptyRect(&rct))
  1279.                     TEIdle(gActiveTEHndl);
  1280.             }
  1281.         }
  1282.     }
  1283. }
  1284.  
  1285.  
  1286.  
  1287. /*****************************************************************************/
  1288.  
  1289.  
  1290.  
  1291. /* See if the keypress event applies to the TextEdit control, and if it does,
  1292. ** handle it and return non-zero.  If the key caused a change in the TERecord,
  1293. ** return 2.  If the key was handled with no change to the TERecord, return 1. */
  1294.  
  1295. #pragma segment TextEditControl
  1296. short    CTEKey(WindowPtr window, EventRecord *event)
  1297. {
  1298.     TEHandle            te;
  1299.     ControlHandle        viewCtl;
  1300.     short                maxTextLen, selStart, selEnd;
  1301.     short                textSelected, arrowKey, retval;
  1302.     char                key;
  1303.     CTEDataHndl            teData;
  1304.     CTEKeyFilterProcPtr    kproc;
  1305.     CTEFastKeysProcPtr    fproc;
  1306.     short                handled;
  1307.     Boolean                looping, refig, tsmHandled;
  1308.     EventRecord            lclEvent;
  1309.  
  1310.     if (!(te = gActiveTEHndl))                return(0);
  1311.     if ((*gActiveTEHndl)->inPort != window) return(0);
  1312.     if (CTEReadOnly(te))                    return(0);
  1313.     if (!(viewCtl = CTEViewFromTE(te)))        return(0);
  1314.     if ((*viewCtl)->contrlHilite == 255)    return(0);
  1315.  
  1316.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1317.     handled = 0;
  1318.     kproc = (*teData)->keyFilter;
  1319.     if (kproc)
  1320.         if ((*kproc)(te, event, &handled))
  1321.             return(handled);
  1322.  
  1323.     retval = 1;
  1324.  
  1325.     for (refig = looping = false;; looping = true) {
  1326.  
  1327.         if (looping) {
  1328.  
  1329.             if (!(fproc = (*teData)->fastKeys)) {
  1330.                 if (refig) {
  1331.                     CTEAdjustTEBottom(te);
  1332.                     CTEAdjustScrollValues(te);
  1333.                 }
  1334.                 return(retval);
  1335.             }                        /* No fast keys looping proc defined, so leave. */
  1336.  
  1337.             if ((gSystemVersion >= 0x0700) && (HMGetBalloons())) {
  1338.                 if (refig) {
  1339.                     CTEAdjustTEBottom(te);
  1340.                     CTEAdjustScrollValues(te);
  1341.                 }
  1342.                 return(retval);
  1343.             }                        /* Don't call OSEventAvail if balloons are active, since
  1344.                                     ** the help manager may move a balloon when it is called.
  1345.                                     ** If we moved balloons now, that might be bad, since it
  1346.                                     ** is likely that BeginContent was called prior to getting
  1347.                                     ** here.  BeginContent calls BeginUpdate, which munges the
  1348.                                     ** visRgn.  If balloons were managed, then visRgns would get
  1349.                                     ** recalculated, and this would mess up our munged balloon. */
  1350.  
  1351.             event = &lclEvent;
  1352.             if (!OSEventAvail((mDownMask | keyDownMask | autoKeyMask), event)) {
  1353.                 if (refig) {
  1354.                     CTEAdjustTEBottom(te);
  1355.                     CTEAdjustScrollValues(te);
  1356.                 }
  1357.                 return(retval);
  1358.             }
  1359.  
  1360.             if (kproc) {
  1361.                 handled = 0;
  1362.                 if ((*kproc)(te, event, &handled)) {
  1363.                     if (refig) {
  1364.                         CTEAdjustTEBottom(te);
  1365.                         CTEAdjustScrollValues(te);
  1366.                     }
  1367.                     return(retval);
  1368.                 }
  1369.             }
  1370.  
  1371.             if (!(*fproc)(te, event)) {
  1372.                 if (refig) {
  1373.                     CTEAdjustTEBottom(te);
  1374.                     CTEAdjustScrollValues(te);
  1375.                 }
  1376.                 return(retval);
  1377.             }
  1378.  
  1379.             GetOSEvent((mDownMask | keyDownMask | autoKeyMask), event);
  1380.         }
  1381.  
  1382.         maxTextLen = (*teData)->maxTextLen;
  1383.         key        = event->message & charCodeMask;
  1384.         selStart   = (*te)->selStart;
  1385.         selEnd     = (*te)->selEnd;
  1386.         if (selStart > selEnd) {
  1387.             selStart = selEnd;
  1388.             selEnd = (*te)->selStart;
  1389.         }
  1390.         textSelected = (selStart != selEnd);
  1391.         arrowKey     = ((key >= chLeft) && (key <= chDown));
  1392.  
  1393.         if (
  1394.             (textSelected) ||                /* If selection range to be replaced or */
  1395.             (arrowKey) ||                    /* key is an arrow or                    */
  1396.             (key == 8) ||                    /* key is a delete or                   */
  1397.             ((*te)->teLength < maxTextLen)    /* we have space for the key...         */
  1398.         ) {
  1399.             tsmHandled = false;
  1400.             if (gUseTSMTE) {
  1401.                 tsmHandled = TSMEvent(event);
  1402.                 if (tsmHandled)
  1403.                     if (!arrowKey)
  1404.                         retval = 2;
  1405.             }
  1406.             if (!tsmHandled) {
  1407.                 if (arrowKey) {
  1408.                     (*teData)->newUndo = true;
  1409.                     TEKey(key, te);
  1410.                 }
  1411.                 else {
  1412.                     CTENewUndo(viewCtl, false);        /* Process the character... */
  1413.                     TEKey(key, te);
  1414.                     retval = 2;
  1415.                 }
  1416.             }
  1417.             refig = true;
  1418.         }
  1419.     }
  1420. }
  1421.  
  1422.  
  1423.  
  1424. static short    dummyCTEKey(WindowPtr window, EventRecord *event)
  1425. {
  1426. #ifndef __MWERKS__
  1427. #pragma unused (window, event)
  1428. #endif
  1429.     return(0);
  1430. }
  1431.  
  1432.  
  1433.  
  1434. /*****************************************************************************/
  1435.  
  1436.  
  1437.  
  1438. /* This function is used to move a TextEdit control.  Pass it the TextEdit
  1439. ** record to move, plus the new position.  It will move the TextEdit control,
  1440. ** along with any scrollbars the control may have.  All areas that need
  1441. ** updating are cleared and invalidated. */
  1442.  
  1443. #pragma segment TextEditControl
  1444. void    CTEMove(TEHandle teHndl, short newH, short newV)
  1445. {
  1446.     WindowPtr        oldPort;
  1447.     Rect            viewRct, brdrRct, rct;
  1448.     short            i, dx, dy, mode;
  1449.     Boolean            hScroll, vScroll;
  1450.     ControlHandle    viewCtl, ctl;
  1451.     CTEDataHndl        teData;
  1452.     char            vis;
  1453.  
  1454.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  1455.  
  1456.     GetPort(&oldPort);
  1457.     SetPort((*teHndl)->inPort);
  1458.  
  1459.     viewRct = (*viewCtl)->contrlRect;
  1460.     vis     = (*viewCtl)->contrlVis;
  1461.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1462.     brdrRct = (*teData)->brdrRect;
  1463.     mode    = (*teData)->mode;
  1464.  
  1465.     dx = newH - viewRct.left;
  1466.     dy = newV - viewRct.top;
  1467.     if ((!dx) && (!dy)) return;
  1468.  
  1469.     hScroll = (mode & cteHScroll) ? 1 : 0;
  1470.     vScroll = (mode & cteVScroll) ? 1 : 0;
  1471.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  1472.  
  1473.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  1474.     if (!EmptyRect(&brdrRct))
  1475.         UnionRect(&rct, &brdrRct, &rct);
  1476.     if (vScroll)
  1477.         rct.right += 15;
  1478.     if (hScroll)
  1479.         rct.bottom += 15;
  1480.     if (mode & cteShowActive)
  1481.         InsetRect(&rct, -4, -4);
  1482.     if (vis) {
  1483.         EraseRect(&rct);
  1484.         InvalRect(&rct);
  1485.     }
  1486.  
  1487.     for (i = 0; i < 2; ++i) {
  1488.         ctl = CTEScrollFromView(viewCtl, i);
  1489.         if (ctl) {
  1490.             rct = (*ctl)->contrlRect;
  1491.             MoveControl(ctl, rct.left + dx, rct.top + dy);
  1492.         }
  1493.     }
  1494.  
  1495.     OffsetRect(&viewRct, dx, dy);
  1496.     if (vis) InvalRect(&viewRct);
  1497.     OffsetRect(&brdrRct, dx, dy);
  1498.     if (vis) InvalRect(&brdrRct);
  1499.  
  1500.     (*viewCtl)->contrlRect = viewRct;
  1501.     (*teData)->brdrRect    = brdrRct;
  1502.  
  1503.     OffsetRect(&(*teHndl)->destRect, dx, dy);
  1504.     OffsetRect(&(*teHndl)->viewRect, dx, dy);
  1505.  
  1506.     viewRct.top  = viewRct.bottom - 16;
  1507.     viewRct.left = viewRct.right  - 16;
  1508.  
  1509.     if (vis)
  1510.         if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll))
  1511.             EraseRect(&viewRct);
  1512.  
  1513.     if (mode & (cteVScrollLessGrow - cteVScroll))
  1514.         OffsetRect(&viewRct, 16, 0);
  1515.     if (mode & (cteHScrollLessGrow - cteHScroll))
  1516.         OffsetRect(&viewRct, 0, 16);
  1517.     if (vis) InvalRect(&viewRct);
  1518.  
  1519.     SetPort(oldPort);
  1520. }
  1521.  
  1522.  
  1523.  
  1524. /*****************************************************************************/
  1525.  
  1526.  
  1527.  
  1528. /* Create a new TextEdit control.  See the comments at the beginning of this
  1529. ** file for more information.  Note that this function doesn't get a dummy,
  1530. ** as you really mean to have this code if you call it.  It calls CTEInitialize(),
  1531. ** just to make sure that the proc pointers are set to point to the real function,
  1532. ** instead of the dummy functions.  By having CLTENew() call CTEInitialize(), the
  1533. ** application won't have to worry about calling CTEInitialize().  By the time that
  1534. ** the application is using a TextEdit control, the proc pointers will be initialized. */
  1535.  
  1536. #pragma segment TextEditControl
  1537. OSErr    CTENew(short viewID, Boolean vis, WindowPtr window, TEHandle *teHndl, Rect *cRect, Rect *dRect,
  1538.                Rect *vRect, Rect *bRect, short maxTextLen, short mode)
  1539. {
  1540.     Rect            ctlRct, destRct, viewRct, brdrRct, scrollRct;
  1541.     WindowPtr        oldPort;
  1542.     TEHandle        te;
  1543.     short            width, height, lh, a;
  1544.     ControlHandle    viewCtl, hScrollCtl, vScrollCtl;
  1545.     CTEDataHndl        teData;
  1546.     TextStyle        styl;
  1547.     OSErr            err;
  1548.     TSMDocumentID    docID;
  1549.     TSMTERecHandle    tsmRec;
  1550.     static OSType    supportedInterfaceTypes[] = {kTSMTEInterfaceType};
  1551.  
  1552.     CTEInitialize();
  1553.  
  1554.     if (teHndl)
  1555.         *teHndl = nil;            /* Assume that we will fail. */
  1556.  
  1557.     GetPort(&oldPort);
  1558.     SetPort(window);
  1559.  
  1560.     ctlRct  = *cRect;
  1561.     destRct = *dRect;
  1562.     viewRct = *vRect;
  1563.     brdrRct = *bRect;
  1564.         /* Make sure that the rects are not in memory that may move. */
  1565.  
  1566.     te = TEStyleNew(&destRct, &viewRct);            /* Do the main thing. */
  1567.  
  1568.     err = noErr;
  1569.     viewCtl = hScrollCtl = vScrollCtl = nil;
  1570.         /* Prepare for various failures. */
  1571.  
  1572.     docID = nil;
  1573.  
  1574.     if (te) {        /* If we were able to create the TextEdit record... */
  1575.  
  1576.         if(gUseTSMTE) {
  1577.             if (!(err = NewTSMDocument(1, supportedInterfaceTypes, &docID, (long)&tsmRec))) {
  1578.                 (*tsmRec)->textH           = te;
  1579.                 (*tsmRec)->preUpdateProc  = nil;
  1580.                 (*tsmRec)->postUpdateProc = (TSMPostUpdateProcPtr)&TSMTEUpdateProc;
  1581.                 (*tsmRec)->updateFlag     = 0;
  1582.                 (*tsmRec)->refCon         = 0;
  1583.             }
  1584.         }
  1585.  
  1586.         if (mode & cteCenterJustify)
  1587.             TESetAlignment(1, te);
  1588.  
  1589.         if (mode & cteRightJustify)
  1590.             TESetAlignment(-1, te);
  1591.  
  1592.         TEGetStyle(0, &styl, &lh, &a, te);
  1593.         if (styl.tsFont == 1) {
  1594.             styl.tsFont = GetAppFont();
  1595.             styl.tsSize = GetDefFontSize();
  1596.             TESetStyle((doFont | doSize), &styl, false, te);
  1597.         }
  1598.  
  1599.         TEAutoView(true, te);
  1600.             /* Let TextEdit 3.0 do most of the scrolling work. */
  1601.  
  1602.         gDefaultClikLoopUPP = (*te)->clickLoop;
  1603. #if USES68KINLINES
  1604.         (*te)->clickLoop = (ProcPtr)ASMTECLIKLOOP;
  1605. #else
  1606.         if (!gClikLoopUPP) {
  1607.             gClikLoopUPP = NewTEClickLoopProc(PPCClikLoop);
  1608.             TESetClickLoop(gClikLoopUPP, te);
  1609.         }
  1610. #endif
  1611.         
  1612.  
  1613.         if (!gCDEF) {
  1614.             gCDEF = (cdefRsrcJMPHndl)GetResource('CDEF', (viewID / 16));
  1615.             if (!gCDEF) return(resNotFound);
  1616.  
  1617.             if (!gCTECtlUPP) {
  1618.                 gCTECtlUPP = NewControlDefProc(CTECtl);
  1619.             }
  1620.             (*gCDEF)->jmpAddress = (long)gCTECtlUPP;
  1621.             if (TrapExists(_HWPriv))
  1622.                 FlushInstructionCache();
  1623.                     /* Make sure that instruction caches don't kill us. */
  1624.         }
  1625.  
  1626.         if (mode & cteHScroll) {        /* Caller wants a horizontal scrollbar... */
  1627.             SetRect(&scrollRct, 0, 0, 100, 16);
  1628.             hScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1629.             if (hScrollCtl) {
  1630.                 MoveControl(hScrollCtl, brdrRct.left, brdrRct.bottom - 1);
  1631.                 width = brdrRct.right - brdrRct.left;
  1632.                 if (mode & (cteHScrollLessGrow - cteHScroll))
  1633.                     if (!(mode & cteVScroll))
  1634.                         width -= 15;
  1635.                 SizeControl(hScrollCtl, width, 16);
  1636.                     /* Line the scrollbar up with the borderRct. */
  1637.             }
  1638.             else err = resNotFound;
  1639.         }
  1640.  
  1641.         if (mode & cteVScroll) {        /* Caller wants a vertical scrollbar... */
  1642.             SetRect(&scrollRct, 0, 0, 16, 100);
  1643.             vScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1644.             if (vScrollCtl) {
  1645.                 MoveControl(vScrollCtl, brdrRct.right - 1, brdrRct.top);
  1646.                 height = brdrRct.bottom - brdrRct.top;
  1647.                 if (mode & (cteVScrollLessGrow - cteVScroll))
  1648.                     if (!(mode & cteHScroll))
  1649.                         height -= 15;
  1650.                 SizeControl(vScrollCtl, 16, height);
  1651.                     /* Line the scrollbar up with the borderRct. */
  1652.             }
  1653.             else err = resNotFound;
  1654.         }
  1655.  
  1656.         viewCtl = NewControl(window, &ctlRct, "\p", false, 0, 0, 0, viewID, (long)te);
  1657.             /* Use our custom view cdef.  It's wierd, but it's small. */
  1658.  
  1659.         if (!viewCtl)
  1660.             err = resNotFound;
  1661.         else {
  1662.             if (hScrollCtl)
  1663.                 SetControlReference(hScrollCtl, (long)viewCtl);
  1664.             if (vScrollCtl)
  1665.                 SetControlReference(vScrollCtl, (long)viewCtl);
  1666.             (*viewCtl)->contrlData = nil;
  1667.             teData = (CTEDataHndl)NewHandleClear(sizeof(CTEDataRec));
  1668.             if (teData) {
  1669.                 (*teData)->maxTextLen   = maxTextLen;
  1670.                 (*teData)->newUndo      = true;
  1671.                 (*teData)->mode         = mode;
  1672.                 (*teData)->brdrRect     = brdrRct;
  1673.                 (*teData)->brdrRect     = brdrRct;
  1674.                 if (!(mode & cteNoFastKeys))
  1675.                     (*teData)->fastKeys = GoFast;
  1676.                 (*teData)->docID        = docID;
  1677.                 (*viewCtl)->contrlData  = (Handle)teData;
  1678.             }
  1679.             else {
  1680.                 err = memFullErr;
  1681.                 if (docID)
  1682.                     DeleteTSMDocument(docID);
  1683.             }
  1684.         }
  1685.     }
  1686.     else err = memFullErr;
  1687.  
  1688.     SetPort(oldPort);
  1689.  
  1690.     if (err) {        /* Oops.  Somebody wasn't happy. */
  1691.         if (viewCtl)
  1692.             DisposeControl(viewCtl);
  1693.                 /* This also disposes of TextEdit handle! */
  1694.         else
  1695.             if (te)
  1696.                 TEDispose(te);
  1697.                     /* We have to dispose of the TextEdit handle ourselves if
  1698.                     ** creating the view control failed. */
  1699.  
  1700.         te = nil;        /* Indicate that there is no TextEdit control. */
  1701.  
  1702.         if (hScrollCtl)
  1703.             DisposeControl(hScrollCtl);
  1704.                 /* More clean-up. */
  1705.  
  1706.         if (vScrollCtl)
  1707.             DisposeControl(vScrollCtl);
  1708.                 /* And still more clean-up. */
  1709.     }
  1710.     else {
  1711.         if (mode & cteActive)
  1712.             CTEActivate(true, te);
  1713.  
  1714.         if (vis) ShowStyledControl(viewCtl);        /* Since everything worked, show the control. */
  1715.  
  1716.         if (mode & cteReadOnly) {
  1717.             if (!gNoCaretHookUPP) {
  1718. #if USES68KINLINES
  1719.                 gNoCaretHookUPP = (ProcPtr)ASMNOCARET;
  1720. #else
  1721.                 gNoCaretHookUPP = NewCaretHookProc(PPCNoCaret);
  1722. #endif
  1723.             }
  1724.             (*te)->caretHook = gNoCaretHookUPP;
  1725.                 /* If read-only, then disable caret for this TextEdit control. */
  1726.         }
  1727.  
  1728.         if (teHndl)
  1729.             *teHndl = te;
  1730.         CTEAdjustScrollValues(te);
  1731.             /* Give the scrollbars an initial value.  This is because the
  1732.             ** TextEdit control could have been created with
  1733.             ** destRct.top < viewRct.top or destRct.left < viewRct.left.
  1734.             ** I don't know why anyone would want to, but it is legal.
  1735.             */
  1736.     }
  1737.  
  1738.     return(err);
  1739. }
  1740.  
  1741. static Boolean    GoFast(TEHandle teHndl, EventRecord *event)
  1742. {
  1743. #ifndef __MWERKS__
  1744. #pragma unused (teHndl)
  1745. #endif
  1746.  
  1747.     char    key;
  1748.  
  1749.     if (event->modifiers & cmdKey) return(false);
  1750.     key = event->message & charCodeMask;
  1751.     if (key == chTab) return(false);
  1752.  
  1753.     return(true);
  1754. }
  1755.  
  1756.  
  1757.  
  1758. /*****************************************************************************/
  1759.  
  1760.  
  1761.  
  1762. /* Save the data (if appropriate) so that user can undo. */
  1763.  
  1764. #pragma segment TextEditControl
  1765. void    CTENewUndo(ControlHandle viewCtl, Boolean alwaysNewUndo)
  1766. {
  1767.     TEHandle        teHndl;
  1768.     CTEDataHndl        teData;
  1769.     Handle            hText, uText;
  1770.     StScrpHandle    hStyl, uStyl;
  1771.  
  1772.     if (!viewCtl) return;
  1773.  
  1774.     teHndl = (TEHandle)GetControlReference(viewCtl);
  1775.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1776.  
  1777.     if ((!alwaysNewUndo) && (!(*teData)->newUndo)) return;
  1778.         /* If there isn't a new undo to record, then just return. */
  1779.  
  1780.     hText = (*teHndl)->hText;
  1781.     hStyl = CTEGetFullStylScrap(teHndl);
  1782.     uText = (*teData)->undoText;
  1783.     uStyl = (*teData)->undoStyl;
  1784.         /* hText/hStyl is styled text in the TextEdit record that is being edited.  */
  1785.         /* uText/uStyl is the undo data (if any) prior to current edit task. */
  1786.  
  1787.     if (uText) {                /* Dump the old undo info, if any. */
  1788.         DisposeHandle(uText);
  1789.         (*teData)->undoText = nil;
  1790.     }
  1791.     if (uStyl) {
  1792.         DisposeHandle((Handle)uStyl);
  1793.         (*teData)->undoStyl = nil;
  1794.     }
  1795.  
  1796.     if (!hStyl) return;
  1797.         /* Not enough ram to record undo, so leave. */
  1798.  
  1799.     uText = hText;
  1800.     if (HandToHand(&uText)) {            /* Copy the text (if ram available). */
  1801.         DisposeHandle((Handle)hStyl);
  1802.         return;                            /* Not enough ram to record undo. */
  1803.     }
  1804.  
  1805.     (*teData)->undoText     = uText;
  1806.     (*teData)->undoStyl     = hStyl;
  1807.     (*teData)->newUndo      = false;
  1808.     (*teData)->undoSelStart = (*teHndl)->selStart;
  1809.     (*teData)->undoSelEnd   = (*teHndl)->selEnd;
  1810. }
  1811.  
  1812.  
  1813.  
  1814. /*****************************************************************************/
  1815.  
  1816.  
  1817.  
  1818. /* Get the next TextEdit control in the window.  You pass it a control handle
  1819. ** for the view control, or nil to start at the beginning of the window.
  1820. ** It returns both a TextEdit handle and the view control handle for that
  1821. ** TextEdit record.  If none is found, nil is returned.  This allows you to
  1822. ** repeatedly call this function and walk through all the TextEdit controls
  1823. ** in a window. */
  1824.  
  1825. #pragma segment TextEditControl
  1826. ControlHandle    CTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1827. {
  1828.     short            i;
  1829.     ControlHandle    nextCtl, priorCtl;
  1830.  
  1831.     if (teHndl)
  1832.         *teHndl = nil;
  1833.  
  1834.     if (!window) return(nil);
  1835.     if (!gCDEF)  return(nil);
  1836.  
  1837.     if (dir > 0) {
  1838.         if (!ctl)
  1839.             ctl = ((WindowPeek)window)->controlList;
  1840.         else
  1841.             ctl = (*ctl)->nextControl;
  1842.         while (ctl) {
  1843.             if ((!justActive) || ((*ctl)->contrlVis)) {
  1844.                 if ((!justActive) || ((*ctl)->contrlHilite != 255)) {
  1845.                     if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gCDEF)) {
  1846.                             /* The handle may be locked, which means that the hi-bit
  1847.                             ** may be on, thus invalidating the compare.  Dereference the
  1848.                             ** handles to get rid of this possibility. */
  1849.                         if (teHndl)
  1850.                             *teHndl = (TEHandle)GetControlReference(ctl);
  1851.                         return(ctl);
  1852.                     }
  1853.                 }
  1854.             }
  1855.             ctl = (*ctl)->nextControl;
  1856.         }
  1857.         return(ctl);
  1858.     }
  1859.  
  1860.     nextCtl = ((WindowPeek)window)->controlList;
  1861.     for (i = 1, priorCtl = nil; ;nextCtl = (*nextCtl)->nextControl, ++i) {
  1862.         if ((!nextCtl) || (nextCtl == ctl)) {
  1863.             if (priorCtl)
  1864.                 if (teHndl)
  1865.                     *teHndl = (TEHandle)GetControlReference(priorCtl);
  1866.             return(priorCtl);
  1867.         }
  1868.         if ((!justActive) || ((*nextCtl)->contrlVis)) {
  1869.             if ((!justActive) || ((*nextCtl)->contrlHilite != 255)) {
  1870.                 if (StripAddress((*nextCtl)->contrlDefProc) == StripAddress(gCDEF))
  1871.                     priorCtl = nextCtl;
  1872.             }
  1873.         }
  1874.     }
  1875. }
  1876.  
  1877.  
  1878.  
  1879. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1880. {
  1881. #ifndef __MWERKS__
  1882. #pragma unused (window, ctl, dir, justActive)
  1883. #endif
  1884.     *teHndl = nil;
  1885.     return(nil);
  1886. }
  1887.  
  1888.  
  1889.  
  1890. /*****************************************************************************/
  1891.  
  1892.  
  1893.  
  1894. /* Return the number of lines of text.  This is because there is a bug in
  1895. ** TextEdit where the number of lines returned is incorrect if the text
  1896. ** ends with a c/r.  This function adjusts for this bug. */
  1897.  
  1898. #pragma segment TextEditControl
  1899. short    CTENumTextLines(TEHandle teHndl)
  1900. {
  1901.     short    lines;
  1902.     char    *cptr;
  1903.  
  1904.     if (!teHndl) return(0);
  1905.  
  1906.     lines = (*teHndl)->nLines;
  1907.  
  1908.     cptr = *((*teHndl)->hText);        /* Pointer to first TextEdit character. */
  1909.     if (cptr[(*teHndl)->teLength - 1] == kCrChar)
  1910.         ++lines;
  1911.             /* Since nLines isn’t right if the last character is a return,
  1912.             ** check for that case and fix it. */
  1913.  
  1914.     return(lines);
  1915. }
  1916.  
  1917.  
  1918.  
  1919. /*****************************************************************************/
  1920.  
  1921.  
  1922.  
  1923. /* Use this function to print the contents of a TextEdit record.  Pass it a
  1924. ** TextEdit handle, a pointer to a text offset, and a pointer to a rect to
  1925. ** print the text in.  The offset should be initialized to what character
  1926. ** in the TextEdit record you wish to start printing at (most likely 0).
  1927. ** The print function prints as much text as will fit in the rect, and
  1928. ** then updates the offset to tell you what is the first character that didn't
  1929. ** print.  You can then call the print function again with another rect with
  1930. ** this new offset, and it will print the text starting at the new offset.
  1931. ** This method is very useful when a single TextEdit record is longer than a
  1932. ** single page, and you wish the text to break at the end of the page.
  1933. ** The bottom of rect is also updated, along with the offset.  The bottom edge
  1934. ** of the rect is changed to reflect the actual bottom of the text printed.
  1935. ** This is useful because the rect passed in didn't necessarily hold an
  1936. ** integer number of lines of text.  The bottom of the rect is adjusted so
  1937. ** it exactly holds complete lines of text.
  1938. ** It is also possible that the rect could hold substantially more lines of
  1939. ** text than there are remaining.  Again, in this situation, the bottom of
  1940. ** rect is adjusted so that the rect tightly bounds the text printed.
  1941. ** The remaining piece of information passed back is an indicator that the
  1942. ** text through the end of the TextEdit record was printed.  When the end
  1943. ** of the text is reached, the offset for the next text to be printed is
  1944. ** returned as -1.  This indicates that processing of the TextEdit record
  1945. ** is complete. */
  1946.  
  1947. #pragma segment TextEditControl
  1948. OSErr    CTEPrint(TEHandle teHndl, short *teOffset, Rect *teRct)
  1949. {
  1950.     short            len, offset, numLines, rctHeight, selStart, selEnd, lnum, y, lh;
  1951.     Handle            hText;
  1952.     Rect            keepDestRct, keepViewRct;
  1953.     WindowPtr        printPort;
  1954.     StScrpHandle    fullStyl, partStyl;
  1955.  
  1956.     if (!teHndl) return(noErr);
  1957.  
  1958.     len = (*teHndl)->teLength;
  1959.     if ((offset = *teOffset) >= len) {
  1960.         *teOffset = -1;                    /* We are offset further than we have text. */
  1961.         teRct->bottom = teRct->top;        /* Empty rect, since no text to draw.  */
  1962.         return(noErr);                    /* Just say that we have no more text. */
  1963.     }
  1964.  
  1965.     if (!(hText = NewHandle(len - offset))) return(memFullErr);
  1966.         /* Can't make part-text handle, so leave. */
  1967.  
  1968.     BlockMove((*(*teHndl)->hText) + offset, *hText, len - offset);
  1969.         /* hText now holds all characters after offset. */
  1970.  
  1971.     fullStyl = CTEGetFullStylScrap(teHndl);
  1972.     if (!fullStyl) {
  1973.         DisposeHandle(hText);        /* Couldn't get styles, so clean up and leave. */
  1974.         return(memFullErr);
  1975.     }
  1976.  
  1977.     partStyl = fullStyl;                    /* This assignment tests for styled TE, and if there */
  1978.     if (partStyl) {                            /* is none, then partStyl gets initialized to nil.   */
  1979.  
  1980.         selStart = (*teHndl)->selStart;        /* Get all styles after the offset. */
  1981.         selEnd   = (*teHndl)->selEnd;
  1982.         (*teHndl)->selStart = offset;
  1983.         (*teHndl)->selEnd   = (*teHndl)->teLength;
  1984.         partStyl = TEGetStyleScrapHandle(teHndl);
  1985.         (*teHndl)->selStart = selStart;
  1986.         (*teHndl)->selEnd   = selEnd;
  1987.         if (!partStyl) {
  1988.             DisposeHandle((Handle)fullStyl);
  1989.             DisposeHandle(hText);
  1990.             return(memFullErr);
  1991.         }
  1992.     }
  1993.  
  1994.     keepDestRct = (*teHndl)->destRect;
  1995.     keepViewRct = (*teHndl)->viewRect;
  1996.     gTEWindow   = (*teHndl)->inPort;
  1997.         /* Cache some information from the TextEdit record. */
  1998.  
  1999.     GetPort(&printPort);
  2000.     (*teHndl)->inPort = printPort;
  2001.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  2002.         /* Install the print rect into the TextEdit record so CTESwapText
  2003.         ** recalcs against the print text. */
  2004.  
  2005.     hText = CTESwapText(teHndl, hText, partStyl, false);
  2006.     DisposeHandle((Handle)partStyl);
  2007.         /* We now have all of the text starting at offset formatted correctly in the print rect. */
  2008.  
  2009.     rctHeight = teRct->bottom - teRct->top;
  2010.     numLines  = CTENumTextLines(teHndl);
  2011.     for (y = 0, lnum = 1; lnum <= numLines; ++lnum) {
  2012.         lh = CTEGetLineHeight(teHndl, lnum, nil);
  2013.         if (y + lh > rctHeight) break;
  2014.         y += lh;
  2015.     }
  2016.     teRct->bottom = teRct->top + y;
  2017.     
  2018.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  2019.         /* We now have the minimum rectangle to hold as much of the text
  2020.         ** as would fit into the rectangle passed in.  The final calc on
  2021.         ** the rect prevents partial lines from being drawn. */
  2022.  
  2023.     TEUpdate(teRct, teHndl);        /* Draw this portion of the text. */
  2024.  
  2025.     if (--lnum >= numLines)
  2026.         *teOffset = -1;
  2027.             /* Printed the last of the text for this record. */
  2028.     else
  2029.         *teOffset = (*teHndl)->lineStarts[lnum] + offset;
  2030.             /* Offset to the first character not printed. */
  2031.  
  2032.     (*teHndl)->inPort   = gTEWindow;
  2033.     gTEWindow           = nil;
  2034.     (*teHndl)->destRect = keepDestRct;
  2035.     (*teHndl)->viewRect = keepViewRct;
  2036.  
  2037.     DisposeHandle(CTESwapText(teHndl, hText, fullStyl, false));
  2038.     DisposeHandle((Handle)fullStyl);
  2039.  
  2040.     return(noErr);            /* Everything worked. */
  2041. }
  2042.  
  2043.  
  2044.  
  2045. /*****************************************************************************/
  2046.  
  2047.  
  2048.  
  2049. /* Return if the TextEdit control is read/write (true) or read-only (false). */
  2050.  
  2051. #pragma segment TextEditControl
  2052. Boolean    CTEReadOnly(TEHandle teHndl)
  2053. {
  2054.     if (teHndl)
  2055.         if (gNoCaretHookUPP)
  2056.             if ((*teHndl)->caretHook == gNoCaretHookUPP)
  2057.                 return(true);
  2058.  
  2059.     return(false);
  2060. }
  2061.  
  2062.  
  2063.  
  2064. /*****************************************************************************/
  2065.  
  2066.  
  2067.  
  2068. /* Return the control handle for the TextEdit control's scrollbar, either
  2069. ** vertical or horizontal.  If the scrollbar doesn't, nil is returned. */
  2070.  
  2071. #pragma segment TextEditControl
  2072. ControlHandle    CTEScrollFromTE(TEHandle teHndl, Boolean vertScroll)
  2073. {
  2074.     ControlHandle    viewCtl;
  2075.  
  2076.     if (!(viewCtl = CTEViewFromTE(teHndl))) return(nil);
  2077.  
  2078.     return(CTEScrollFromView(viewCtl, vertScroll));
  2079. }
  2080.  
  2081.  
  2082.  
  2083. /*****************************************************************************/
  2084.  
  2085.  
  2086.  
  2087. /* Return the control handle for the scrollbar related to the view control,
  2088. ** either horizontal or vertical.  If the scrollbar doesn't exist, return nil. */
  2089.  
  2090. #pragma segment TextEditControl
  2091. ControlHandle    CTEScrollFromView(ControlHandle viewCtl, Boolean vertScroll)
  2092. {
  2093.     ControlHandle    ctl;
  2094.     WindowPtr        window;
  2095.     Boolean            vert;
  2096.  
  2097.     if (!viewCtl) return(nil);
  2098.  
  2099.     window = (*viewCtl)->contrlOwner;
  2100.     ctl    = ((WindowPeek)window)->controlList;
  2101.  
  2102.     for (; ctl;) {
  2103.         if ((ControlHandle)GetControlReference(ctl) == viewCtl) {
  2104.             vert = false;
  2105.             if ((*ctl)->contrlRect.right == (*ctl)->contrlRect.left + 16)
  2106.                 vert = true;
  2107.             if (vert == vertScroll) return(ctl);
  2108.         }
  2109.         ctl = (*ctl)->nextControl;
  2110.     }
  2111.     return(nil);
  2112. }
  2113.  
  2114.  
  2115.  
  2116. /*****************************************************************************/
  2117.  
  2118.  
  2119.  
  2120. /* A TextEdit control can have an optional key filter, which is called whenever
  2121. ** CTEKey() is called.  If you pass in nil, then the filtering is turned off.
  2122. ** This allows individual TextEdit controls to handle their own filtering.
  2123. ** The filter procedure is of the form:
  2124. **     Boolean (*CTEKeyFilterProcPtr)(TEHandle teHndl, EventRecord *event, short *handled);
  2125. ** If true is returned, then CTEKey() is aborted, and the value in "handled" is
  2126. ** returned.  By having a separate abort value and return value, you can determine
  2127. ** if processing of the event should be continued or not, independent of whether
  2128. ** or not you aborted CTEKey(). */
  2129.  
  2130. #pragma segment TextEditControl
  2131. void    CTESetKeyFilter(TEHandle teHndl, CTEKeyFilterProcPtr proc)
  2132. {
  2133.     ControlHandle    viewCtl;
  2134.     CTEDataHndl        teData;
  2135.  
  2136.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2137.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2138.     (*teData)->keyFilter = proc;
  2139. }
  2140.  
  2141.  
  2142.  
  2143. /*****************************************************************************/
  2144.  
  2145.  
  2146.  
  2147. #pragma segment TextEditControl
  2148. void    CTESetFastKeys(TEHandle teHndl, CTEFastKeysProcPtr proc)
  2149. {
  2150.     ControlHandle    viewCtl;
  2151.     CTEDataHndl        teData;
  2152.  
  2153.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2154.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2155.     (*teData)->fastKeys = proc;
  2156. }
  2157.  
  2158.  
  2159.  
  2160. /*****************************************************************************/
  2161.  
  2162.  
  2163.  
  2164. /* Select a range of text.  TESetSelect can't be used alone because it doesn't
  2165. ** update the scrollbars.  This function calls TESetSelect, and then fixes up
  2166. ** the scrollbars. */
  2167.  
  2168. #pragma segment TextEditControl
  2169. void    CTESetSelect(short start, short end, TEHandle teHndl)
  2170. {
  2171.     WindowPtr        oldPort;
  2172.     ControlHandle    viewCtl;
  2173.     CTEDataHndl        teData;
  2174.  
  2175.     if (teHndl) {
  2176.         GetPort(&oldPort);
  2177.         SetPort((*teHndl)->inPort);
  2178.         TESetSelect(start, end, teHndl);
  2179.         CTEAdjustScrollValues(teHndl);
  2180.         viewCtl = CTEViewFromTE(teHndl);
  2181.         if (viewCtl) {
  2182.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2183.             (*teData)->newUndo = true;
  2184.         }
  2185.         SetPort(oldPort);
  2186.     }
  2187. }
  2188.  
  2189.  
  2190.  
  2191. static void    dummyCTESetSelect(short start, short end, TEHandle teHndl)
  2192. {
  2193. #ifndef __MWERKS__
  2194. #pragma unused (start, end, teHndl)
  2195. #endif
  2196. }
  2197.  
  2198.  
  2199.  
  2200. /*****************************************************************************/
  2201.  
  2202.  
  2203.  
  2204. /* Show the designated TextEdit control and related scrollbars. */
  2205.  
  2206. #pragma segment TextEditControl
  2207. void    CTEShow(TEHandle teHndl)
  2208. {
  2209.     ControlHandle    viewCtl, scrollCtl;
  2210.     short            i;
  2211.  
  2212.     viewCtl = CTEViewFromTE(teHndl);
  2213.     if (viewCtl) {
  2214.         ShowStyledControl(viewCtl);
  2215.         for (i = 0; i < 2; i++) {
  2216.             scrollCtl = CTEScrollFromView(viewCtl, i);
  2217.             if (scrollCtl)
  2218.                 ShowStyledControl(scrollCtl);
  2219.         }
  2220.     }
  2221. }
  2222.  
  2223.  
  2224.  
  2225. /*****************************************************************************/
  2226.  
  2227.  
  2228.  
  2229. /* This function is used to resize a TextEdit control.  Pass it the TextEdit
  2230. ** record to resize, plus the new horizontal and vertical size.  It will
  2231. ** resize the TextEdit control, realign the text, if necessary, plus it will
  2232. ** resize and adjust any scrollbars the TextEdit control may have.  All areas
  2233. ** that need updating are cleared and invalidated. */
  2234.  
  2235. #pragma segment TextEditControl
  2236. void    CTESize(TEHandle teHndl, short newH, short newV, Boolean newDest)
  2237. {
  2238.     WindowPtr        oldPort;
  2239.     Rect            viewRct, brdrRct, teViewRct, oldTeViewRct, rct;
  2240.     short            i, dx, dy, mode, hScroll, vScroll;
  2241.     ControlHandle    viewCtl, ctl[2];
  2242.     CTEDataHndl        teData;
  2243.     RgnHandle        rgn1, rgn2;
  2244.     char            vis;
  2245.  
  2246.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2247.  
  2248.     GetPort(&oldPort);
  2249.     SetPort((*teHndl)->inPort);
  2250.  
  2251.     viewRct = (*viewCtl)->contrlRect;
  2252.     vis     = (*viewCtl)->contrlVis;
  2253.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2254.     brdrRct = (*teData)->brdrRect;
  2255.     mode    = (*teData)->mode;
  2256.  
  2257.     dx = newH - (viewRct.right  - viewRct.left);
  2258.     dy = newV - (viewRct.bottom - viewRct.top);
  2259.     if ((!dx) && (!dy)) return;
  2260.  
  2261.     hScroll = (mode & cteHScroll) ? 1 : 0;
  2262.     vScroll = (mode & cteVScroll) ? 1 : 0;
  2263.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  2264.  
  2265.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  2266.     if (!EmptyRect(&brdrRct))
  2267.         UnionRect(&rct, &brdrRct, &rct);
  2268.     if (vScroll)
  2269.         rct.right += 15;
  2270.     if (hScroll)
  2271.         rct.bottom += 15;
  2272.     if (mode & cteShowActive)
  2273.         InsetRect(&rct, -4, -4);
  2274.     if (vis) {
  2275.         EraseRect(&rct);
  2276.         InvalRect(&rct);
  2277.     }
  2278.  
  2279.     for (i = 0; i < 2; ++i) {
  2280.         ctl[i] = CTEScrollFromView(viewCtl, i);
  2281.         if (ctl[i]) {
  2282.             rct = (*ctl[i])->contrlRect;
  2283.             if (i) {
  2284.                 HideControl(ctl[i]);
  2285.                 SizeControl(ctl[i], rct.right - rct.left, rct.bottom - rct.top + dy);
  2286.                 MoveControl(ctl[i], rct.left + dx, rct.top);
  2287.             }
  2288.             else {
  2289.                 HideControl(ctl[i]);
  2290.                 SizeControl(ctl[i], rct.right - rct.left + dx, rct.bottom - rct.top);
  2291.                 MoveControl(ctl[i], rct.left, rct.top + dy);
  2292.             }
  2293.         }
  2294.     }        /* Reposition the scrollbars, if we have any. */
  2295.  
  2296.     if (vis) InvalRect(&viewRct);        /* Resize our view control. */
  2297.     viewRct.right  += dx;
  2298.     viewRct.bottom += dy;
  2299.     (*viewCtl)->contrlRect = viewRct;
  2300.     if (vis) InvalRect(&viewRct);
  2301.  
  2302.     if (vis) InvalRect(&brdrRct);        /* Resize our border rect. */
  2303.     brdrRct.right  += dx;
  2304.     brdrRct.bottom += dy;
  2305.     (*teData)->brdrRect = brdrRct;
  2306.     if (vis) InvalRect(&brdrRct);
  2307.  
  2308.     teViewRct = oldTeViewRct = (*teHndl)->viewRect;        /* Resize TextEdit viewRect. */
  2309.     teViewRct.right  += dx;
  2310.     teViewRct.bottom += dy;
  2311.     (*teHndl)->viewRect = teViewRct;
  2312.  
  2313.     if (newDest) {        /* Resize TextEdit destRect, if so indicated. */
  2314.         (*teHndl)->destRect.right  += dx;
  2315.         (*teHndl)->destRect.bottom += dy;
  2316.         TECalText(teHndl);
  2317.         if (vis) {
  2318.             EraseRect(&oldTeViewRct);        /* Redraw the whole thing if destRect changes. */
  2319.             InvalRect(&oldTeViewRct);
  2320.         }
  2321.     }
  2322.  
  2323.     if (vis) {
  2324.         rgn1 = NewRgn();
  2325.         rgn2 = NewRgn();
  2326.         RectRgn(rgn1, &oldTeViewRct);        /* Clear old areas if we are shrinking. */
  2327.         RectRgn(rgn2, &teViewRct);
  2328.         DiffRgn(rgn1, rgn2, rgn2);
  2329.         EraseRgn(rgn2);
  2330.         InvalRgn(rgn2);
  2331.         RectRgn(rgn2, &teViewRct);            /* Update new areas if we are growing. */
  2332.         DiffRgn(rgn2, rgn1, rgn2);
  2333.         InvalRgn(rgn2);
  2334.         DisposeRgn(rgn1);
  2335.         DisposeRgn(rgn2);
  2336.     }
  2337.  
  2338.     if (vis)
  2339.         for (i = 0; i < 2; ++i)
  2340.             if (ctl[i])
  2341.                 ShowStyledControl(ctl[i]);
  2342.                     /* Show the controls in their new position. */
  2343.  
  2344.     if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll)) {
  2345.         rct = viewRct;
  2346.         rct.top  = rct.bottom - 16;
  2347.         rct.left = rct.right - 16;
  2348.         if (mode & (cteVScrollLessGrow - cteVScroll))
  2349.             OffsetRect(&rct, 16, 0);
  2350.         if (mode & (cteHScrollLessGrow - cteHScroll))
  2351.             OffsetRect(&rct, 0, 16);
  2352.         if (vis) {
  2353.             EraseRect(&rct);
  2354.             InvalRect(&rct);
  2355.         }
  2356.     }
  2357.  
  2358.     CTEAdjustTEBottom(teHndl);
  2359.     CTEAdjustScrollValues(teHndl);
  2360.  
  2361.     SetPort(oldPort);
  2362. }
  2363.  
  2364.  
  2365.  
  2366. /*****************************************************************************/
  2367.  
  2368.  
  2369.  
  2370. /* Swap the TextEdit text handle with the text handle passed in. */
  2371.  
  2372. #pragma segment TextEditControl
  2373. Handle    CTESwapText(TEHandle teHndl, Handle newText, StScrpHandle styl, Boolean update)
  2374. {
  2375.     WindowPtr        oldPort;
  2376.     Handle            oldText;
  2377.     Rect            destRct, viewRct;
  2378.     TextStyle        srun;
  2379.     ScrpSTElement    s;
  2380.     ControlHandle    viewCtl;
  2381.     CTEDataHndl        teData;
  2382.     RgnHandle        oldClip, newClip;
  2383.  
  2384.     if (!teHndl) return(nil);
  2385.  
  2386.     GetPort(&oldPort);
  2387.     SetPort((*teHndl)->inPort);
  2388.  
  2389.     oldText = (*teHndl)->hText;
  2390.     HandToHand(&oldText);
  2391.  
  2392.     HLock(newText);
  2393.     TESetText(*newText, 0, teHndl);                            /* Make there be only 1 style run. */
  2394.     TESetText(*newText, GetHandleSize(newText), teHndl);    /* Put the correct text in the record. */
  2395.     DisposeHandle(newText);
  2396.  
  2397.     viewCtl = CTEViewFromTE(teHndl);
  2398.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2399.     if (!((*teData)->mode & cteRightJustify)) {
  2400.         if (!(*viewCtl)->contrlVis) {
  2401.             GetClip(oldClip = NewRgn());
  2402.             SetClip(newClip = NewRgn());
  2403.         }
  2404.         TESetSelect(0, 0, teHndl);
  2405.         if (!(*viewCtl)->contrlVis) {
  2406.             SetClip(oldClip);
  2407.             DisposeRgn(oldClip);
  2408.             DisposeRgn(newClip);
  2409.         }
  2410.     }
  2411.  
  2412.     if (styl) {
  2413.         CTESetStylScrap(0, (*teHndl)->teLength, styl, teHndl);        /* Apply style to all text. */
  2414.         if ((*teHndl)->selStart)                                    /* Apply style to caret loc. */
  2415.             s = (*styl)->scrpStyleTab[0];
  2416.         else
  2417.             s = (*styl)->scrpStyleTab[(*styl)->scrpNStyles - 1];
  2418.         srun.tsFont  = s.scrpFont;
  2419.         srun.tsFace  = s.scrpFace;
  2420.         srun.tsSize  = s.scrpSize;
  2421.         srun.tsColor = s.scrpColor;
  2422.         TESetStyle(doAll, &srun, false, teHndl);
  2423.     }
  2424.  
  2425.     GetClip(oldClip = NewRgn());        /* Force the nullStyle to become active. */
  2426.     SetClip(newClip = NewRgn());        /* This also resizes the caret to reflect nullStyle size. */
  2427.     TEKey(' ', teHndl);
  2428.     TEKey(8, teHndl);
  2429.     SetClip(oldClip);
  2430.     DisposeRgn(oldClip);
  2431.     DisposeRgn(newClip);
  2432.  
  2433.     TECalText(teHndl);
  2434.  
  2435.     if (update) {
  2436.         destRct = (*teHndl)->destRect;
  2437.         viewRct = (*teHndl)->viewRect;
  2438.  
  2439.         OffsetRect(&destRct,
  2440.             viewRct.left - destRct.left,
  2441.             viewRct.top  - destRct.top);
  2442.  
  2443.         (*teHndl)->destRect = destRct;
  2444.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2445.  
  2446.         CTEUpdate(teHndl, CTEViewFromTE(teHndl), false);
  2447.     }
  2448.  
  2449.     CTEAdjustTEBottom(teHndl);        /* Fix these things up, whether showing or not. */
  2450.     CTEAdjustScrollValues(teHndl);
  2451.  
  2452.     SetPort(oldPort);
  2453.     return(oldText);
  2454. }
  2455.  
  2456.  
  2457.  
  2458. /*****************************************************************************/
  2459.  
  2460.  
  2461.  
  2462. /* Return information for the currently active TextEdit control.  The currently
  2463. ** active TextEdit control is stored in gActiveTEHndl, and can be accessed
  2464. ** directly.  If gActiveTEHndl is nil, then there is no currently active one.
  2465. ** The information that we return is the viewRect and window of the active
  2466. ** TextEdit control.  This is information that could be gotten directly, but
  2467. ** this call makes it a little more convenient. */
  2468.  
  2469. #pragma segment TextEditControl
  2470. WindowPtr    CTETargetInfo(TEHandle *teHndl, Rect *teView)
  2471. {
  2472.     if (teView)
  2473.         SetRect(teView, 0, 0, 0, 0);
  2474.  
  2475.     if (teHndl)
  2476.         *teHndl = gActiveTEHndl;
  2477.  
  2478.     if (!gActiveTEHndl) return(nil);
  2479.  
  2480.     if (teView)
  2481.         *teView = (*gActiveTEHndl)->viewRect;
  2482.  
  2483.     return((*gActiveTEHndl)->inPort);
  2484. }
  2485.  
  2486.  
  2487.  
  2488. /*****************************************************************************/
  2489.  
  2490.  
  2491.  
  2492. /* Perform an undo function for the TextEdit control. */
  2493.  
  2494. #pragma segment TextEditControl
  2495. ControlHandle    CTEUndo(void)
  2496. {
  2497.     TEHandle        teHndl;
  2498.     ControlHandle    viewCtl;
  2499.     CTEDataHndl        teData;
  2500.     Handle            hText, uText;
  2501.     StScrpHandle    hStyl, uStyl;
  2502.     short            oldStart, oldEnd;
  2503.  
  2504.     if (!(teHndl = gActiveTEHndl)) return(nil);
  2505.  
  2506.     viewCtl = CTEViewFromTE(teHndl);
  2507.     if (viewCtl) {
  2508.         oldStart = (*teHndl)->selStart;
  2509.         oldEnd   = (*teHndl)->selEnd;
  2510.  
  2511.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2512.  
  2513.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2514.         hText  = (*teHndl)->hText;
  2515.         uText  = (*teData)->undoText;
  2516.         if (!uText) return(nil);        /* There is no undo yet.  Getting called in this state is
  2517.                                         ** actually an error, but we check, just in case. */
  2518.  
  2519.         hStyl = CTEGetFullStylScrap(teHndl);
  2520.         uStyl = (*teData)->undoStyl;
  2521.  
  2522.         (*teData)->undoText = CTESwapText(teHndl, (*teData)->undoText, uStyl, false);
  2523.         DisposeHandle((Handle)uStyl);
  2524.         (*teData)->undoStyl = hStyl;
  2525.  
  2526.         CTEUpdate(teHndl, viewCtl, false);
  2527.         TESetSelect((*teData)->undoSelStart, (*teData)->undoSelEnd, teHndl);
  2528.         CTEAdjustTEBottom(teHndl);
  2529.         CTEAdjustScrollValues(teHndl);
  2530.  
  2531.         (*teData)->newUndo      = true;
  2532.         (*teData)->undoSelStart = oldStart;
  2533.         (*teData)->undoSelEnd   = oldEnd;
  2534.     }
  2535.  
  2536.     return(viewCtl);
  2537. }
  2538.  
  2539.  
  2540.  
  2541. /*****************************************************************************/
  2542.  
  2543.  
  2544.  
  2545. /* Draw the TextEdit control and frame. */
  2546.  
  2547. #pragma segment TextEditControl
  2548. void    CTEUpdate(TEHandle teHndl, ControlHandle ctl, Boolean justShowActive)
  2549. {
  2550.     WindowPtr    oldPort, tePort;
  2551.     Rect        viewRct, brdrRct, rr;
  2552.     CTEDataHndl    teData;
  2553.     short        mode;
  2554.  
  2555.     if (teHndl) {
  2556.         if ((*ctl)->contrlVis) {
  2557.  
  2558.             GetPort(&oldPort);
  2559.             SetPort(tePort = (*teHndl)->inPort);
  2560.  
  2561.             teData  = (CTEDataHndl)(*ctl)->contrlData;
  2562.             mode    = (*teData)->mode;
  2563.             viewRct = (*teHndl)->viewRect;
  2564.             brdrRct = (*teData)->brdrRect;
  2565.  
  2566.             if (!justShowActive) {
  2567.                 if (!EmptyRect(&brdrRct)) {
  2568.                     if (!(mode & cteNoBorder)) {
  2569.                         FrameRect(&brdrRct);
  2570.                         InsetRect(&brdrRct, 1, 1);
  2571.                         EraseRect(&brdrRct);
  2572.                         InsetRect(&brdrRct, -1, -1);
  2573.                     }
  2574.                     else {
  2575.                         rr = brdrRct;
  2576.                         if (mode & cteVScroll) --rr.bottom;
  2577.                         if (mode & cteHScroll) --rr.right;
  2578.                         EraseRect(&rr);
  2579.                     }
  2580.                 }
  2581.                 else EraseRect(&viewRct);
  2582.                 TEUpdate(&viewRct, teHndl);
  2583.             }
  2584.     
  2585.             if (mode & cteShowActive) {
  2586.                 if (!EmptyRect(&brdrRct)) {
  2587.                     InsetRect(&brdrRct, -3, -3);
  2588.                     if (mode & cteVScroll)
  2589.                         brdrRct.right  += 15;
  2590.                     if (mode & cteHScroll)
  2591.                         brdrRct.bottom += 15;
  2592.                     if ((!((WindowPeek)tePort)->hilited) || (teHndl != gActiveTEHndl))
  2593.                         PenPat((ConstPatternParam)&qd.white);
  2594.                     PenSize(2, 2);
  2595.                     FrameRect(&brdrRct);
  2596.                     InsetRect(&brdrRct, 2, 2);
  2597.                     PenSize(1, 1);
  2598.                     PenPat((ConstPatternParam)&qd.white);
  2599.                     FrameRect(&brdrRct);
  2600.                     PenNormal();
  2601.                 }
  2602.             }
  2603.  
  2604.             SetPort(oldPort);
  2605.         }
  2606.     }
  2607. }
  2608.  
  2609.  
  2610.  
  2611. /*****************************************************************************/
  2612.  
  2613.  
  2614.  
  2615. /* Return the control handle for the view control that owns the TextEdit
  2616. ** record.  Use this to find the view to do customizations such as changing
  2617. ** the update procedure for this TextEdit control. */
  2618.  
  2619. #pragma segment TextEditControl
  2620. ControlHandle    CTEViewFromTE(TEHandle teHndl)
  2621. {
  2622.     WindowPtr        window;
  2623.     ControlHandle    viewCtl;
  2624.     TEHandle        te;
  2625.  
  2626.     if (!teHndl) return(nil);
  2627.  
  2628.     if (!(window = gTEWindow))
  2629.         window = (WindowPtr)(*teHndl)->inPort;
  2630.  
  2631.     for (viewCtl = nil;;) {
  2632.  
  2633.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  2634.         if ((!viewCtl) || (te == teHndl)) return(viewCtl);
  2635.     }
  2636. }
  2637.  
  2638.  
  2639.  
  2640. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl)
  2641. {
  2642. #ifndef __MWERKS__
  2643. #pragma unused (teHndl)
  2644. #endif
  2645.     return(nil);
  2646. }
  2647.  
  2648.  
  2649.  
  2650. /*****************************************************************************/
  2651.  
  2652.  
  2653.  
  2654. /* Call this when a window with TextEdit controls is being activated.  This
  2655. ** will make the TextEdit control that was last active in this window the
  2656. ** active TextEdit control again. */
  2657.  
  2658. #pragma segment TextEditControl
  2659. TEHandle    CTEWindActivate(WindowPtr window, Boolean displayIt)
  2660. {
  2661.     short            hilite, scrollNum;
  2662.     ControlHandle    viewCtl, scrollCtl;
  2663.     TEHandle        te;
  2664.     CTEDataHndl        teData;
  2665.  
  2666.     if (!window) return(nil);
  2667.  
  2668.     hilite = 255;
  2669.     if (((WindowPeek)window)->hilited)
  2670.         hilite = 0;
  2671.  
  2672.     for (viewCtl = nil; (viewCtl = CTENext(window, &te, viewCtl, 1, true)) != nil;) {
  2673.  
  2674.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2675.         if (!((*teData)->mode & cteActive)) continue;
  2676.  
  2677.         if (displayIt) {
  2678.  
  2679.             if (!hilite)
  2680.                 CTEActivate(true, te);
  2681.             else
  2682.                 CTEActivate(false, te);
  2683.  
  2684.             for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2685.                 scrollCtl = CTEScrollFromTE(te, scrollNum);
  2686.                 if (scrollCtl)
  2687.                     HiliteControl(scrollCtl, hilite);
  2688.             }
  2689.         }
  2690.  
  2691.         if (hilite)
  2692.             te = nil;
  2693.  
  2694.         return(te);
  2695.     }
  2696.  
  2697.     return(nil);
  2698. }
  2699.  
  2700.  
  2701.  
  2702. static TEHandle    dummyCTEWindActivate(WindowPtr window, Boolean displayIt)
  2703. {
  2704. #ifndef __MWERKS__
  2705. #pragma unused (window, displayIt)
  2706. #endif
  2707.  
  2708.     return(nil);
  2709. }
  2710.  
  2711.  
  2712.  
  2713. /*****************************************************************************/
  2714.  
  2715.  
  2716.  
  2717. /* This function is called after an edit to make sure that there is no extra
  2718. ** white space at the bottom of the viewRect.  If there are blank lines at
  2719. ** the bottom of the viewRect, and there is text scrolled off the top of the
  2720. ** viewRect, then the TextEdit control is scrolled to fill this space, or as
  2721. ** much of it as possible. */
  2722.  
  2723. #pragma segment TextEditControl
  2724. void    CTEAdjustTEBottom(TEHandle teHndl)
  2725. {
  2726.     Rect    destRct, viewRct;
  2727.     short    botDiff, topDiff;
  2728.  
  2729.     destRct = (*teHndl)->destRect;
  2730.     viewRct = (*teHndl)->viewRect;
  2731.     destRct.bottom = destRct.top + CTEDocHeight(teHndl);
  2732.  
  2733.     botDiff = viewRct.bottom - destRct.bottom;
  2734.  
  2735.     if (botDiff > 0) {
  2736.         topDiff = viewRct.top - destRct.top;
  2737.         if (botDiff > topDiff)
  2738.             botDiff = topDiff;
  2739.         if (botDiff)
  2740.             TEScroll(0, botDiff, teHndl);
  2741.     }
  2742. }
  2743.  
  2744.  
  2745.  
  2746. /*****************************************************************************/
  2747.  
  2748.  
  2749.  
  2750. /* Bring the scrollbar values up to date with the current document position
  2751. ** and length. */
  2752.  
  2753. #pragma segment TextEditControl
  2754. void    CTEAdjustScrollValues(TEHandle teHndl)
  2755. {
  2756.     short            scrollNum;
  2757.     ControlHandle    scrollCtl;
  2758.  
  2759.     for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2760.         scrollCtl = CTEScrollFromTE(teHndl, scrollNum);
  2761.         if (scrollCtl)
  2762.             AdjustOneScrollValue(teHndl, scrollCtl, scrollNum);
  2763.     }
  2764. }
  2765.  
  2766.  
  2767.  
  2768. /*****************************************************************************/
  2769.  
  2770.  
  2771.  
  2772. #pragma segment TextEditControl
  2773. StScrpHandle    CTEGetFullStylScrap(TEHandle teHndl)
  2774. {
  2775.     short            selStart, selEnd;
  2776.     StScrpHandle    styl;
  2777.  
  2778.     selStart = (*teHndl)->selStart;
  2779.     selEnd   = (*teHndl)->selEnd;
  2780.  
  2781.     (*teHndl)->selStart = 0;
  2782.     (*teHndl)->selEnd   = (*teHndl)->teLength;
  2783.  
  2784.     styl = TEGetStyleScrapHandle(teHndl);
  2785.  
  2786.     (*teHndl)->selStart = selStart;
  2787.     (*teHndl)->selEnd   = selEnd;
  2788.  
  2789.     return(styl);
  2790. }
  2791.  
  2792.  
  2793.  
  2794. /*****************************************************************************/
  2795.  
  2796.  
  2797.  
  2798. #pragma segment TextEditControl
  2799. void    CTESetStylScrap(short begRng, short endRng, StScrpHandle styles, TEHandle teHndl)
  2800. {
  2801.     short            n, i, b, e, selStart, selEnd;
  2802.     ScrpSTElement    styl, s;
  2803.     TextStyle        srun;
  2804.     TEStyleHandle    shndl;
  2805.  
  2806.     if (!styles) return;
  2807.  
  2808.     shndl = TEGetStyleHandle(teHndl);
  2809.  
  2810.     selStart = (*teHndl)->selStart;
  2811.     selEnd   = (*teHndl)->selEnd;
  2812.  
  2813.     n = (*styles)->scrpNStyles;
  2814.  
  2815.     for (i = 0; i < n;) {
  2816.         styl = (*styles)->scrpStyleTab[i++];
  2817.         b  = styl.scrpStartChar;
  2818.         if (i == n)
  2819.             e = endRng;
  2820.         else {
  2821.             s = (*styles)->scrpStyleTab[i];
  2822.             e = s.scrpStartChar;
  2823.         }
  2824.         if (b >= endRng) break;            /* We're past the range for style application. */
  2825.         if (e <= begRng) continue;        /* We're not to the range for style application. */
  2826.  
  2827.         if (b < begRng) b = begRng;        /* Clip to range for style application. */
  2828.         if (e > endRng) e = endRng;
  2829.  
  2830.         if (b < e) {
  2831.             srun.tsFont  = styl.scrpFont;
  2832.             srun.tsFace  = styl.scrpFace;
  2833.             srun.tsSize  = styl.scrpSize;
  2834.             srun.tsColor = styl.scrpColor;
  2835.             (*teHndl)->selStart = b;
  2836.             (*teHndl)->selEnd   = e;
  2837.             TESetStyle(doAll, &srun, false, teHndl);
  2838.             TECalText(teHndl);
  2839.         }
  2840.     }
  2841.  
  2842.     (*teHndl)->selStart = selStart;
  2843.     (*teHndl)->selEnd   = selEnd;
  2844. }
  2845.  
  2846.  
  2847.  
  2848. /*****************************************************************************/
  2849.  
  2850.  
  2851.  
  2852. #pragma segment TextEditControl
  2853. short    CTEGetLineNum(TEHandle te, short offset)
  2854. {
  2855.     short    i;
  2856.  
  2857.     for (i = 0; i < (*te)->nLines; ++i)
  2858.         if ((*te)->lineStarts[i] > offset)
  2859.             break;
  2860.  
  2861.     return(i);
  2862. }
  2863.  
  2864.  
  2865.  
  2866. /*****************************************************************************/
  2867.  
  2868.  
  2869.  
  2870. #pragma segment TextEditControl
  2871. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent)
  2872. {
  2873.     TEStyleHandle    tes;
  2874.     LHHandle        lhh;
  2875.  
  2876.     tes = *(TEStyleHandle *)&((*te)->txFont);
  2877.     lhh = (*tes)->lhTab;
  2878.  
  2879.     if (ascent) *ascent = (*lhh)[lineNum - 1].lhAscent;
  2880.     return((*lhh)[--lineNum].lhHeight);
  2881. }
  2882.  
  2883.  
  2884.  
  2885. /*****************************************************************************/
  2886.  
  2887.  
  2888.  
  2889. #pragma segment TextEditControl
  2890. void    CTEGetPStr(ControlHandle ctl, StringPtr pstr)
  2891. {
  2892.     TEHandle        te;
  2893.     unsigned short    len;
  2894.  
  2895.     if (!ctl) return;
  2896.     te = (TEHandle)GetControlReference(ctl);
  2897.     if (!te) return;
  2898.  
  2899.     len = (*te)->teLength;
  2900.     if (len > 255) len = 255;
  2901.  
  2902.     BlockMove(*(*te)->hText, pstr + 1, *pstr = len);
  2903. }
  2904.  
  2905.  
  2906.  
  2907. /*****************************************************************************/
  2908.  
  2909.  
  2910.  
  2911. #pragma segment TextEditControl
  2912. void    CTEPutPStr(ControlHandle ctl, StringPtr pstr)
  2913. {
  2914.     CTESetPStr(ctl, pstr);
  2915. }
  2916.  
  2917.  
  2918.  
  2919. /*****************************************************************************/
  2920.  
  2921.  
  2922.  
  2923. #pragma segment TextEditControl
  2924. void    CTESetPStr(ControlHandle ctl, StringPtr pstr)
  2925. {
  2926.     TEHandle    te;
  2927.     Handle        h;
  2928.  
  2929.     if (!ctl) return;
  2930.     te = (TEHandle)GetControlReference(ctl);
  2931.     if (!te) return;
  2932.  
  2933.     h = NewHandle(pstr[0]);
  2934.     if (h) {
  2935.         BlockMove(pstr + 1, *h, pstr[0]);
  2936.         DisposeHandle(CTESwapText(te, h, nil, true));
  2937.     }
  2938. }
  2939.  
  2940.  
  2941.  
  2942. /*****************************************************************************/
  2943. /*****************************************************************************/
  2944.  
  2945.  
  2946.  
  2947. #pragma segment TextEditControl
  2948. static pascal void    VActionProc(ControlHandle scrollCtl, short part)
  2949. {
  2950.     short        delta, value, teOffset;
  2951.     short        oldValue, max, lh, as;
  2952.     TEHandle    te;
  2953.     TextStyle    styl;
  2954.     
  2955.     if (part) {                        /* If it was actually in the control. */
  2956.  
  2957.         te = gActiveTEHndl;
  2958.         TEGetStyle((*te)->selStart, &styl, &lh, &as, te);
  2959.         switch (part) {
  2960.             case inUpButton:
  2961.             case inDownButton:        /* One line. */
  2962.                 delta = lh;
  2963.                 break;
  2964.             case inPageUp:            /* One page. */
  2965.             case inPageDown:
  2966.                 delta = (*te)->viewRect.bottom - (*te)->viewRect.top;
  2967.                 if (delta > lh)
  2968.                     delta -= lh;
  2969.                 break;
  2970.         }
  2971.         if ( (part == inUpButton) || (part == inPageUp) )
  2972.             delta = -delta;        /* Reverse direction for an upper. */
  2973.  
  2974.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  2975.         if (value < 0)
  2976.             value = 0;
  2977.         if (value > (max = GetControlMaximum(scrollCtl)))
  2978.             value = max;
  2979.  
  2980.         if (value != oldValue) {
  2981.             SetControlValue(scrollCtl, value);
  2982.             teOffset = (*te)->viewRect.top - (*te)->destRect.top;
  2983.             if (value -= teOffset)
  2984.                 TEScroll(0, -value, te);
  2985.         }
  2986.     }
  2987. }
  2988.  
  2989.  
  2990.  
  2991. /*****************************************************************************/
  2992.  
  2993.  
  2994.  
  2995. #pragma segment TextEditControl
  2996. static pascal void    HActionProc(ControlHandle scrollCtl, short part)
  2997. {
  2998.     short        delta, value, teOffset;
  2999.     short        oldValue, max;
  3000.     TEHandle    te;
  3001.     
  3002.     if (part) {                        /* If it was actually in the control. */
  3003.  
  3004.         te = gActiveTEHndl;
  3005.         switch (part) {
  3006.             case inUpButton:
  3007.             case inDownButton:        /* One line. */
  3008.                 delta = 16;
  3009.                 break;
  3010.             case inPageUp:            /* One page. */
  3011.             case inPageDown:
  3012.                 delta = (*te)->viewRect.right - (*te)->viewRect.left;
  3013.                 if (delta > 16)
  3014.                     delta -= 16;
  3015.                 break;
  3016.         }
  3017.         if ( (part == inUpButton) || (part == inPageUp) )
  3018.             delta = -delta;        /* Reverse direction for an upper. */
  3019.  
  3020.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  3021.         if (value < 0)
  3022.             value = 0;
  3023.         if (value > (max = GetControlMaximum(scrollCtl)))
  3024.             value = max;
  3025.  
  3026.         if (value != oldValue) {
  3027.             SetControlValue(scrollCtl, value);
  3028.             teOffset = (*te)->viewRect.left - (*te)->destRect.left;
  3029.             if (value -= teOffset)
  3030.                 TEScroll(-value, 0, te);
  3031.         }
  3032.     }
  3033. }
  3034.  
  3035.  
  3036.  
  3037. /*****************************************************************************/
  3038.  
  3039.  
  3040.  
  3041. /* Bring one scrollbar value up to date with the current document position
  3042. ** and length. */
  3043.  
  3044. #pragma segment TextEditControl
  3045. static void    AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert)
  3046. {
  3047.     Boolean    front;
  3048.     short    textPix, viewPix;
  3049.     short    max, oldMax, value, oldValue;
  3050.  
  3051.     front = ((WindowPeek)(*ctl)->contrlOwner)->hilited;
  3052.  
  3053.     oldValue = GetControlValue(ctl);
  3054.     oldMax   = GetControlMaximum(ctl);
  3055.  
  3056.     if (vert) {
  3057.         textPix = CTEDocHeight(teHndl);
  3058.         viewPix = (*teHndl)->viewRect.bottom - (*teHndl)->viewRect.top;
  3059.     }
  3060.     else {
  3061.         textPix = (*teHndl)->destRect.right - (*teHndl)->destRect.left;
  3062.         viewPix = (*teHndl)->viewRect.right - (*teHndl)->viewRect.left;
  3063.     }
  3064.     max = textPix - viewPix;
  3065.  
  3066.     if (max < 0)
  3067.         max = 0;
  3068.     if (max != oldMax) {
  3069.         if (front)
  3070.             SetControlMaximum(ctl, max);
  3071.         else
  3072.             (*ctl)->contrlMax = max;
  3073.     }
  3074.  
  3075.     if (vert)
  3076.         value = (*teHndl)->viewRect.top  - (*teHndl)->destRect.top;
  3077.     else
  3078.         value = (*teHndl)->viewRect.left - (*teHndl)->destRect.left;
  3079.  
  3080.     if (value < 0)
  3081.         value = 0;
  3082.     if (value > max)
  3083.         value = max;
  3084.     if (value != oldValue) {
  3085.         if (front)
  3086.             SetControlValue(ctl, value);
  3087.         else
  3088.             (*ctl)->contrlValue = value;
  3089.     }
  3090. }
  3091.  
  3092.  
  3093.  
  3094. /*****************************************************************************/
  3095.  
  3096.  
  3097.  
  3098. #pragma segment TextEditControl
  3099. Boolean    CTEUseTSMTE(void)
  3100. {
  3101.     return(gUseTSMTE = TSMTEAvailable());
  3102. }
  3103.  
  3104.  
  3105.  
  3106. /*****************************************************************************/
  3107.  
  3108.  
  3109.  
  3110. #pragma segment TextEditControl
  3111. Boolean    TSMTEAvailable(void)
  3112. {
  3113.     long    response;
  3114.     
  3115.     if (Gestalt(kTSMTESignature, &response)) return(false);
  3116.  
  3117.     return((response & (1 << gestaltTSMTE)) != 0);
  3118. }
  3119.  
  3120.  
  3121.  
  3122. /*****************************************************************************/
  3123.  
  3124.  
  3125.  
  3126. #pragma segment TextEditControl
  3127. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  3128.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon)
  3129. {
  3130. #ifndef __MWERKS__
  3131. #pragma unused (fixLen, inputAreaStart, inputAreaEnd, pinStart, pinEnd, refCon)
  3132. #endif
  3133.  
  3134.     CTEAdjustTEBottom(te);
  3135.     CTEAdjustScrollValues(te);
  3136. }
  3137.  
  3138.  
  3139.  
  3140. /*****************************************************************************/
  3141.  
  3142.  
  3143.  
  3144. #pragma segment TextEditControl
  3145. Boolean    IsTECtl(ControlHandle ctl)
  3146. {
  3147.     if (ctl)
  3148.         if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gCDEF))
  3149.             return(true);
  3150.                 /* The handle may be locked, which means that the hi-bit
  3151.                 ** may be on, thus invalidating the compare.  Dereference the
  3152.                 ** handles to get rid of this possibility. */
  3153.  
  3154.     return(false);
  3155. }
  3156.  
  3157.  
  3158.  
  3159. /*****************************************************************************/
  3160.  
  3161.  
  3162.  
  3163. /* PPCClikLoop gets called by the TextEdit Manager from TEClick.
  3164. ** It calls the old, default click loop routine that scrolls the
  3165. ** text, and then calls our own Pascal routine that handles
  3166. ** tracking the scroll bars to follow along.  It does the same thing as the
  3167. ** 68K asm routine ASMTECLIKLOOP, but for PowerPC we don't have all the
  3168. ** register concerns. */
  3169.  
  3170. #ifdef powerc
  3171. static pascal Boolean    PPCClikLoop(TEPtr pTE)
  3172. {
  3173.     CallTEClickLoopProc(gDefaultClikLoopUPP, pTE);
  3174.         /* First call TextEdit's default ClikLoop routine */
  3175.  
  3176.     CTEClikLoop();        /* Now call our custom routine */
  3177.     return(true);
  3178. }
  3179.  
  3180. /*****/
  3181.  
  3182. /* PPCNoCaret does the samething as the 68K asm routine ASMNOCARET. Namely -- nothing. */
  3183. static pascal void    PPCNoCaret(const Rect *r, TEPtr pTE)
  3184. {
  3185. #ifndef __MWERKS__
  3186. #pragma unused (boundsRect, pTE)
  3187. #endif
  3188.     return;
  3189. }
  3190. #endif
  3191.  
  3192.  
  3193. #ifndef powerc
  3194. #ifdef __MWERKS__
  3195.  
  3196. asm pascal Boolean ASMTECLIKLOOP(void)
  3197. {
  3198.         movem.l    D1-D2/A1,-(SP)            /* D0 and A0 need not be saved. */
  3199.  
  3200.         movea.l    gDefaultClikLoopUPP,A0
  3201.         jsr    (A0)                        /* Execute TextEdit's default clikLoop. */
  3202.  
  3203.         movem.l    (SP)+,D1-D2/A1            /* Restore the world as it was. */
  3204.         movem.l    D1-D2/A1,-(SP)            /* D0 and A0 need not be saved. */
  3205.  
  3206.         jsr    CTEClikLoop
  3207.  
  3208.         movem.l    (SP)+,D1-D2/A1            /* Restore the world as it was. */
  3209.         moveq    #1,D0                    /* Clear the zero flag so TextEdit keeps going. */
  3210.         rts
  3211. }
  3212.  
  3213. asm pascal void ASMNOCARET(Rect *caretRect)
  3214. {
  3215.         move.l    (A7)+,D0
  3216.         rts
  3217. }
  3218.  
  3219. #endif
  3220. #endif
  3221.